diff --git a/src/CONST.ts b/src/CONST.ts index 6a562093932f..382f26cd3d91 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -824,6 +824,7 @@ const CONST = { REIMBURSEMENT_SETUP: 'REIMBURSEMENTSETUP', // Deprecated OldDot Action REIMBURSEMENT_SETUP_REQUESTED: 'REIMBURSEMENTSETUPREQUESTED', // Deprecated OldDot Action REJECTED: 'REJECTED', + REMOVED_FROM_APPROVAL_CHAIN: 'REMOVEDFROMAPPROVALCHAIN', RENAMED: 'RENAMED', REPORT_PREVIEW: 'REPORTPREVIEW', SELECTED_FOR_RANDOM_AUDIT: 'SELECTEDFORRANDOMAUDIT', // OldDot Action diff --git a/src/languages/en.ts b/src/languages/en.ts index 702d06e4dfee..99dad19fbbfb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3851,6 +3851,19 @@ export default { }, workspaceActions: { renamedWorkspaceNameAction: ({oldName, newName}) => `updated the name of this workspace from ${oldName} to ${newName}`, + removedFromApprovalWorkflow: ({submittersNames}: {submittersNames: string[]}) => { + let joinedNames = ''; + if (submittersNames.length === 1) { + joinedNames = submittersNames[0]; + } else if (submittersNames.length === 2) { + joinedNames = submittersNames.join(' and '); + } else if (submittersNames.length > 2) { + joinedNames = `${submittersNames.slice(0, submittersNames.length - 1).join(', ')} and ${submittersNames[submittersNames.length - 1]}`; + } + const workflowWord = Str.pluralize('workflow', 'workflows', submittersNames.length); + const chatWord = Str.pluralize('chat', 'chats', submittersNames.length); + return `removed you from ${joinedNames}'s approval ${workflowWord} and workspace ${chatWord}. Previously submitted reports will remain available for approval in your Inbox.`; + }, }, roomMembersPage: { memberNotFound: 'Member not found.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 15e6b42823f9..9e406f197281 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3902,6 +3902,19 @@ export default { }, workspaceActions: { renamedWorkspaceNameAction: ({oldName, newName}) => `actualizó el nombre de este espacio de trabajo de ${oldName} a ${newName}`, + removedFromApprovalWorkflow: ({submittersNames}: {submittersNames: string[]}) => { + let joinedNames = ''; + if (submittersNames.length === 1) { + joinedNames = submittersNames[0]; + } else if (submittersNames.length === 2) { + joinedNames = submittersNames.join(' y '); + } else if (submittersNames.length > 2) { + joinedNames = `${submittersNames.slice(0, submittersNames.length - 1).join(', ')} y ${submittersNames[submittersNames.length - 1]}`; + } + const workflowWord = Str.pluralize('del flujo', 'de los flujos', submittersNames.length); + const chatWord = Str.pluralize('del chat', 'de los chats', submittersNames.length); + return `te eliminó ${workflowWord} de trabajo de aprobaciones y ${chatWord} del espacio de trabajo de ${joinedNames}. Los informes enviados anteriormente seguirán estando disponibles para su aprobación en tu bandeja de entrada.`; + }, }, roomMembersPage: { memberNotFound: 'Miembro no encontrado.', diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 44a2cc62df3c..5a7f6602795c 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1649,13 +1649,21 @@ function getPolicyChangeLogDeleteMemberMessage(reportAction: OnyxInputOrEntry>) { - const initialMessage = getOriginalMessage(reportAction); + const originalMessage = getOriginalMessage(reportAction); return Localize.translateLocal('newRoomPage.renamedRoomAction', { - oldName: initialMessage?.oldName ?? '', - newName: initialMessage?.newName ?? '', + oldName: originalMessage?.oldName ?? '', + newName: originalMessage?.newName ?? '', }); } +function getRemovedFromApprovalChainMessage(reportAction: OnyxEntry>) { + const originalMessage = getOriginalMessage(reportAction); + const submittersNames = PersonalDetailsUtils.getPersonalDetailsByIDs(originalMessage?.submittersAccountIDs ?? [], currentUserAccountID ?? -1).map( + ({displayName, login}) => displayName ?? login ?? 'Unknown Submitter', + ); + return Localize.translateLocal('workspaceActions.removedFromApprovalWorkflow', {submittersNames}); +} + export { doesReportHaveVisibleActions, extractLinksFromMessageHtml, @@ -1682,6 +1690,7 @@ export { getOneTransactionThreadReportID, getOriginalMessage, getParentReportAction, + getRemovedFromApprovalChainMessage, getReportAction, getReportActionHtml, getReportActionMessage, diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 6b504d863664..98b626164146 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -665,6 +665,8 @@ function ReportActionItem({ children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.DELETE_EMPLOYEE) { children = ; + } else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.REMOVED_FROM_APPROVAL_CHAIN)) { + children = ; } else if ( ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED, CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED_VIRTUAL, CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS) ) { diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 763f221f56fe..1e2328688e90 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -491,6 +491,15 @@ type OriginalMessageUnapproved = { expenseReportID: string; }; +/** Model of `Removed From Approval Chain` report action */ +type OriginalMessageRemovedFromApprovalChain = { + /** The submitter IDs whose approval chains changed such that the approver was removed from their approval chains */ + submittersAccountIDs: number[]; + + /** The accountID of the approver who was removed from the submitter's approval chain */ + whisperedTo: number[]; +}; + /** * Model of `Add payment card` report action */ @@ -557,8 +566,9 @@ type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED]: OriginalMessageReimbursementDequeued; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DELAYED]: never; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_QUEUED]: OriginalMessageReimbursementQueued; - [CONST.REPORT.ACTIONS.TYPE.RENAMED]: OriginalMessageRenamed; [CONST.REPORT.ACTIONS.TYPE.REJECTED]: never; + [CONST.REPORT.ACTIONS.TYPE.REMOVED_FROM_APPROVAL_CHAIN]: OriginalMessageRemovedFromApprovalChain; + [CONST.REPORT.ACTIONS.TYPE.RENAMED]: OriginalMessageRenamed; [CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW]: OriginalMessageReportPreview; [CONST.REPORT.ACTIONS.TYPE.SELECTED_FOR_RANDOM_AUDIT]: never; [CONST.REPORT.ACTIONS.TYPE.SHARE]: never;