diff --git a/src/languages/de.ts b/src/languages/de.ts index 0e83514bd0e0..521bd71584ee 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -1356,7 +1356,7 @@ const translations: TranslationDeepObject = { unapproved: `nicht genehmigt`, automaticallyForwarded: `über Genehmigung durch Workspace-Regeln`, forwarded: `genehmigt`, - rejectedThisReport: 'hat diesen Bericht abgelehnt', + rejectedThisReport: 'abgelehnt', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `hat die Zahlung gestartet, wartet aber darauf, dass ${submitterDisplayName} ein Bankkonto hinzufügt.`, adminCanceledRequest: 'hat die Zahlung storniert', canceledRequest: (amount: string, submitterDisplayName: string) => diff --git a/src/languages/en.ts b/src/languages/en.ts index 80af1ce5423f..f290a2e110d9 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1384,7 +1384,7 @@ const translations = { unapproved: `unapproved`, automaticallyForwarded: `approved via workspace rules`, forwarded: `approved`, - rejectedThisReport: 'rejected this report', + rejectedThisReport: 'rejected', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started payment, but is waiting for ${submitterDisplayName} to add a bank account.`, adminCanceledRequest: 'canceled the payment', canceledRequest: (amount: string, submitterDisplayName: string) => diff --git a/src/languages/es.ts b/src/languages/es.ts index fa7d96a27851..49acf1334e39 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1215,7 +1215,7 @@ const translations: TranslationDeepObject = { unapproved: `no aprobado`, automaticallyForwarded: `aprobó mediante reglas del espacio de trabajo`, forwarded: `aprobó`, - rejectedThisReport: 'rechazó este informe', + rejectedThisReport: 'rechazó', waitingOnBankAccount: ({submitterDisplayName}) => `inició el pago, pero está esperando a que ${submitterDisplayName} añada una cuenta bancaria.`, adminCanceledRequest: 'canceló el pago', canceledRequest: (amount, submitterDisplayName) => `canceló el pago ${amount}, porque ${submitterDisplayName} no habilitó tu Billetera Expensify en un plazo de 30 días.`, diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 5ff85ce234f9..3152ec1bb82c 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -1360,7 +1360,7 @@ const translations: TranslationDeepObject = { unapproved: `Non approuvé`, automaticallyForwarded: `approuvé via les règles de l'espace de travail`, forwarded: `approuvé`, - rejectedThisReport: 'a rejeté cette note de frais', + rejectedThisReport: 'rejeté', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `a commencé le paiement, mais attend que ${submitterDisplayName} ajoute un compte bancaire.`, adminCanceledRequest: 'a annulé le paiement', canceledRequest: (amount: string, submitterDisplayName: string) => diff --git a/src/languages/it.ts b/src/languages/it.ts index daa88280e4a3..8dcdde7623bd 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -1354,7 +1354,7 @@ const translations: TranslationDeepObject = { unapproved: `non approvata`, automaticallyForwarded: `approvata tramite le regole dello spazio di lavoro`, forwarded: `approvato`, - rejectedThisReport: 'ha rifiutato questo report', + rejectedThisReport: 'rifiutato', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `ha avviato il pagamento, ma sta aspettando che ${submitterDisplayName} aggiunga un conto bancario.`, adminCanceledRequest: 'ha annullato il pagamento', canceledRequest: (amount: string, submitterDisplayName: string) => diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 56ee7f8d7167..6c5f132d1893 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -1346,7 +1346,7 @@ const translations: TranslationDeepObject = { unapproved: `未承認`, automaticallyForwarded: `ワークスペースルールにより承認済み`, forwarded: `承認済み`, - rejectedThisReport: 'このレポートを却下しました', + rejectedThisReport: '却下しました', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `支払いを開始しましたが、${submitterDisplayName}が銀行口座を追加するのを待っています。`, adminCanceledRequest: '支払いをキャンセルしました', canceledRequest: (amount: string, submitterDisplayName: string) => diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 59c35183dddf..9f6b5bc9386e 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -1353,7 +1353,7 @@ const translations: TranslationDeepObject = { unapproved: `niet-goedgekeurd`, automaticallyForwarded: `goedgekeurd via werkruimteregels`, forwarded: `goedgekeurd`, - rejectedThisReport: 'heeft dit rapport afgekeurd', + rejectedThisReport: 'afgekeurd', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `is een betaling gestart, maar wacht tot ${submitterDisplayName} een bankrekening toevoegt.`, adminCanceledRequest: 'heeft de betaling geannuleerd', canceledRequest: (amount: string, submitterDisplayName: string) => diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 9156a55f6316..a7dffa8fddd5 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -1353,7 +1353,7 @@ const translations: TranslationDeepObject = { unapproved: `niezatwierdzone`, automaticallyForwarded: `zatwierdzone przez reguły przestrzeni roboczej`, forwarded: `zatwierdzono`, - rejectedThisReport: 'odrzucił(-a) ten raport', + rejectedThisReport: 'odrzucono', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `rozpoczęto płatność, ale oczekuje na to, aż ${submitterDisplayName} doda konto bankowe.`, adminCanceledRequest: 'anulowano płatność', canceledRequest: (amount: string, submitterDisplayName: string) => diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index f75660f6acfa..a5b706ca7757 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -1352,7 +1352,7 @@ const translations: TranslationDeepObject = { unapproved: `não aprovado`, automaticallyForwarded: `aprovado por meio das regras do workspace`, forwarded: `aprovado`, - rejectedThisReport: 'rejeitou este relatório', + rejectedThisReport: 'rejeitou', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `iniciou o pagamento, mas está aguardando ${submitterDisplayName} adicionar uma conta bancária.`, adminCanceledRequest: 'cancelou o pagamento', canceledRequest: (amount: string, submitterDisplayName: string) => `cancelou o pagamento de ${amount} porque ${submitterDisplayName} não ativou a Carteira Expensify em 30 dias`, diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 5b8132a876b7..a88d2d8c4dec 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -1326,7 +1326,7 @@ const translations: TranslationDeepObject = { unapproved: `未批准`, automaticallyForwarded: `通过工作区规则批准`, forwarded: `已批准`, - rejectedThisReport: '已拒绝此报表', + rejectedThisReport: '已拒绝', waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `已开始付款,但正在等待${submitterDisplayName}添加银行账户。`, adminCanceledRequest: '已取消付款', canceledRequest: (amount: string, submitterDisplayName: string) => `已取消金额为 ${amount} 的付款,因为 ${submitterDisplayName} 未在 30 天内启用其 Expensify 钱包`, diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index edba10e7eb0a..44ca3184a701 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -93,6 +93,7 @@ import { isPendingRemove, isReimbursementDeQueuedOrCanceledAction, isReimbursementQueuedAction, + isRejectedAction, isRenamedAction, isReportActionVisible, isReportPreviewAction, @@ -791,7 +792,7 @@ function getLastMessageTextForReport({ } else { lastMessageTextFromReport = translate('iou.forwarded'); } - } else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { + } else if (isRejectedAction(lastReportAction)) { lastMessageTextFromReport = translate('iou.rejectedThisReport'); } else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.CORPORATE_UPGRADE) { lastMessageTextFromReport = translate('workspaceActions.upgradedWorkspace'); diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index cf1a309cc0e4..491a9c213196 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -184,7 +184,6 @@ const deprecatedOldDotReportActions = new Set([ CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED, CONST.REPORT.ACTIONS.TYPE.DONATION, CONST.REPORT.ACTIONS.TYPE.REIMBURSED, - CONST.REPORT.ACTIONS.TYPE.REJECTED_TO_SUBMITTER, ]); function isCreatedAction(reportAction: OnyxInputOrEntry): boolean { @@ -568,6 +567,10 @@ function isRetractedAction(reportAction: OnyxEntry): reportAction return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.RETRACTED); } +function isRejectedAction(reportAction: OnyxInputOrEntry): boolean { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REJECTED) || isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REJECTED_TO_SUBMITTER); +} + function isRoomChangeLogAction(reportAction: OnyxEntry): reportAction is ReportAction> { return reportAction?.actionName ? ROOM_CHANGE_LOG_ARRAY.has(reportAction.actionName) : false; } @@ -4592,6 +4595,7 @@ export { getRoomChangeLogMessage, getActionableCard3DSTransactionApprovalMessage, shouldShowActivateCard, + isRejectedAction, isReopenedAction, isRetractedAction, getIntegrationSyncFailedMessage, diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 549e011126d7..72f53786e785 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -92,6 +92,7 @@ import { isMovedAction, isOldDotReportAction, isOriginalReportDeleted, + isRejectedAction, isRenamedAction, isReportActionAttachment, isTagModificationAction, @@ -406,7 +407,7 @@ function computeReportNameBasedOnReportAction( if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.UNHOLD) { return translate('iou.unheldExpense'); } - if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { + if (isRejectedAction(parentReportAction)) { return translate('iou.rejectedThisReport'); } if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RETRACTED) { diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index ae71aade3154..95391bf0e622 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -9632,6 +9632,7 @@ function getDuplicateActionsForPartialReport( CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.UNAPPROVED, CONST.REPORT.ACTIONS.TYPE.REJECTED, + CONST.REPORT.ACTIONS.TYPE.REJECTED_TO_SUBMITTER, CONST.REPORT.ACTIONS.TYPE.RETRACTED, CONST.REPORT.ACTIONS.TYPE.CLOSED, CONST.REPORT.ACTIONS.TYPE.REOPENED, diff --git a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx index 4e334cfdc655..d7353eb181b6 100644 --- a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx @@ -134,6 +134,7 @@ import { isOriginalReportDeleted, isReimbursementDeQueuedOrCanceledAction, isReimbursementQueuedAction, + isRejectedAction, isRenamedAction, isReportActionAttachment, isReportPreviewAction as isReportPreviewActionReportActionsUtils, @@ -940,7 +941,7 @@ const ContextMenuActions: ContextMenuAction[] = [ } else { Clipboard.setString(translate('iou.forwarded')); } - } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { + } else if (isRejectedAction(reportAction)) { Clipboard.setString(translate('iou.rejectedThisReport')); } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.CORPORATE_UPGRADE) { const displayMessage = translate('workspaceActions.upgradedWorkspace'); diff --git a/src/pages/inbox/report/PureReportActionItem.tsx b/src/pages/inbox/report/PureReportActionItem.tsx index aebec325e978..1ba1a1e4c1f1 100644 --- a/src/pages/inbox/report/PureReportActionItem.tsx +++ b/src/pages/inbox/report/PureReportActionItem.tsx @@ -186,6 +186,7 @@ import { isPendingRemove, isReimbursementDeQueuedOrCanceledAction, isReimbursementQueuedAction, + isRejectedAction, isRenamedAction, isResolvedConciergeCategoryOptions, isResolvedConciergeDescriptionOptions, @@ -1431,7 +1432,7 @@ function PureReportActionItem({ } else { children = ; } - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) { + } else if (isRejectedAction(action)) { children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.CORPORATE_UPGRADE) { children = ; diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 4b74456f8d9b..099ed08bcbe5 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -1372,6 +1372,7 @@ type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.HOLD_COMMENT]: never; [CONST.REPORT.ACTIONS.TYPE.INTEGRATIONS_MESSAGE]: OriginalMessageIntegrationMessage; [CONST.REPORT.ACTIONS.TYPE.REJECTED]: never; + [CONST.REPORT.ACTIONS.TYPE.REJECTED_TO_SUBMITTER]: never; [CONST.REPORT.ACTIONS.TYPE.REJECTEDTRANSACTION_THREAD]: never; [CONST.REPORT.ACTIONS.TYPE.REJECTED_TRANSACTION_MARKASRESOLVED]: never; [CONST.REPORT.ACTIONS.TYPE.IOU]: OriginalMessageIOU; diff --git a/tests/unit/ReportActionsUtilsTest.ts b/tests/unit/ReportActionsUtilsTest.ts index 8d742337016c..701b37dde387 100644 --- a/tests/unit/ReportActionsUtilsTest.ts +++ b/tests/unit/ReportActionsUtilsTest.ts @@ -3850,4 +3850,75 @@ describe('ReportActionsUtils', () => { expect(ReportActionsUtils.isOriginalReportDeleted(action, originalReport)).toBe(false); }); }); + describe('isRejectedAction', () => { + it('should return true for REJECTED action type', () => { + // Given a report action with REJECTED action type + const action: ReportAction = { + ...createRandomReportAction(0), + actionName: CONST.REPORT.ACTIONS.TYPE.REJECTED, + created: '2025-11-21', + reportActionID: '1', + originalMessage: undefined, + message: [], + previousMessage: [], + }; + + // When checking if the action is a rejected action + const result = ReportActionsUtils.isRejectedAction(action); + + // Then it should return true + expect(result).toBe(true); + }); + + it('should return true for REJECTED_TO_SUBMITTER action type', () => { + // Given a report action with REJECTED_TO_SUBMITTER action type + const action: ReportAction = { + ...createRandomReportAction(0), + actionName: CONST.REPORT.ACTIONS.TYPE.REJECTED_TO_SUBMITTER, + created: '2025-11-21', + reportActionID: '1', + originalMessage: undefined, + message: [], + previousMessage: [], + }; + + // When checking if the action is a rejected action + const result = ReportActionsUtils.isRejectedAction(action); + + // Then it should return true because REJECTED_TO_SUBMITTER is also a rejected action + expect(result).toBe(true); + }); + + it('should return false for non-rejected action type', () => { + // Given a report action with SUBMITTED action type (not rejected) + const action: ReportAction = { + ...createRandomReportAction(0), + actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED, + created: '2025-11-21', + reportActionID: '1', + originalMessage: { + amount: 10000, + currency: 'USD', + }, + message: [], + previousMessage: [], + }; + + // When checking if the action is a rejected action + const result = ReportActionsUtils.isRejectedAction(action); + + // Then it should return false + expect(result).toBe(false); + }); + + it('should return false for null action', () => { + // Given a null action + + // When checking if the action is a rejected action + const result = ReportActionsUtils.isRejectedAction(null); + + // Then it should return false because the action is null + expect(result).toBe(false); + }); + }); }); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 45e2fee80b09..1c5f234ee26e 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -2382,7 +2382,27 @@ describe('ReportUtils', () => { }; const reportName = computeReportName(threadReport, undefined, undefined, undefined, undefined, participantsPersonalDetails, reportActions); - expect(reportName).toBe('rejected this report'); + expect(reportName).toBe('rejected'); + }); + + test('should return rejected action name for REJECTED_TO_SUBMITTER', () => { + const rejectedToSubmitterAction: ReportAction = { + ...baseParentReportAction, + actionName: CONST.REPORT.ACTIONS.TYPE.REJECTED_TO_SUBMITTER, + }; + + const threadReport: Report = { + ...baseExpenseReport, + parentReportID: baseChatReport.reportID, + parentReportActionID: rejectedToSubmitterAction.reportActionID, + }; + + const reportActions = { + [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${threadReport.parentReportID}`]: {[rejectedToSubmitterAction.reportActionID]: rejectedToSubmitterAction}, + }; + const reportName = computeReportName(threadReport, undefined, undefined, undefined, undefined, participantsPersonalDetails, reportActions); + + expect(reportName).toBe('rejected'); }); test('should handle integration sync failed action', () => {