From 02f023c41c4fdad64e8ffdfb0c6f23d4bc967fd0 Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Thu, 30 Jul 2026 00:59:38 +0700 Subject: [PATCH] Updated functions to accept a translate parameter --- src/libs/ReportUtils.ts | 13 +++-- src/libs/actions/IOU/ReportWorkflow.ts | 46 +++++++++++------ src/libs/actions/Task.ts | 4 +- src/pages/DynamicReportChangeApproverPage.tsx | 4 +- src/pages/ReportAddApproverPage.tsx | 15 +++--- src/pages/Search/SearchAddApproverPage.tsx | 15 +++--- src/pages/Search/SearchChangeApproverPage.tsx | 12 ++++- .../DynamicTaskAssigneeSelectorModal.tsx | 1 + tests/actions/TaskTest.ts | 2 + tests/unit/ReportUtilsTest.ts | 50 +++++++++++++++++++ 10 files changed, 126 insertions(+), 36 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 3a9a1d5b01d7..c543508329b4 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -8611,7 +8611,12 @@ function buildOptimisticCardAssignedReportAction(assigneeAccountID: number, curr }; } -function buildOptimisticChangedTaskAssigneeReportAction(assigneeAccountID: number, currentUserAccountID: number, delegateEmailParam: string | undefined): OptimisticEditedTaskReportAction { +function buildOptimisticChangedTaskAssigneeReportAction( + assigneeAccountID: number, + currentUserAccountID: number, + delegateEmailParam: string | undefined, + translate: LocalizedTranslate, +): OptimisticEditedTaskReportAction { const delegateAccountDetails = delegateEmailParam ? getPersonalDetailByEmail(delegateEmailParam) : undefined; return { @@ -8622,7 +8627,7 @@ function buildOptimisticChangedTaskAssigneeReportAction(assigneeAccountID: numbe message: [ { type: CONST.REPORT.MESSAGE.TYPE.COMMENT, - text: `assigned to ${getDisplayNameForParticipant({accountID: assigneeAccountID, formatPhoneNumber: formatPhoneNumberPhoneUtils})}`, + text: `assigned to ${getDisplayNameForParticipant({accountID: assigneeAccountID, formatPhoneNumber: formatPhoneNumberPhoneUtils, translate})}`, html: `assigned to `, }, ], @@ -8752,7 +8757,7 @@ function buildOptimisticResolvedDuplicatesReportAction(): OptimisticDismissedVio }; } -function buildOptimisticChangeApproverReportAction(managerID: number, actorAccountID: number): OptimisticChangedApproverReportAction { +function buildOptimisticChangeApproverReportAction(managerID: number, actorAccountID: number, translate: LocalizedTranslate): OptimisticChangedApproverReportAction { const created = DateUtils.getDBTime(); return { actionName: managerID === actorAccountID ? CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL : CONST.REPORT.ACTIONS.TYPE.REROUTE, @@ -8762,7 +8767,7 @@ function buildOptimisticChangeApproverReportAction(managerID: number, actorAccou message: [ { type: CONST.REPORT.MESSAGE.TYPE.COMMENT, - text: `changed the approver to ${getDisplayNameForParticipant({accountID: managerID, formatPhoneNumber: formatPhoneNumberPhoneUtils})}`, + text: `changed the approver to ${getDisplayNameForParticipant({accountID: managerID, formatPhoneNumber: formatPhoneNumberPhoneUtils, translate})}`, html: `changed the approver to `, }, ], diff --git a/src/libs/actions/IOU/ReportWorkflow.ts b/src/libs/actions/IOU/ReportWorkflow.ts index fda76294ea2d..3460f4cc2821 100644 --- a/src/libs/actions/IOU/ReportWorkflow.ts +++ b/src/libs/actions/IOU/ReportWorkflow.ts @@ -1,3 +1,5 @@ +import type {LocalizedTranslate} from '@components/LocaleContextProvider'; + import * as API from '@libs/API'; import type { AddReportApproverParams, @@ -1731,8 +1733,9 @@ function assignReportToMe( isASAPSubmitBetaEnabled: boolean, reportCurrentNextStepDeprecated: OnyxEntry, isTrackIntentUser: boolean | undefined, + translate: LocalizedTranslate, ) { - const takeControlReportAction = buildOptimisticChangeApproverReportAction(accountID, accountID); + const takeControlReportAction = buildOptimisticChangeApproverReportAction(accountID, accountID, translate); // buildOptimisticNextStep is used in parallel const optimisticNextStepDeprecated = buildNextStepNew({ @@ -1838,19 +1841,34 @@ function assignReportToMe( API.write(WRITE_COMMANDS.ASSIGN_REPORT_TO_ME, params, onyxData); } -function addReportApprover( - report: OnyxTypes.Report, - newApproverEmail: string, - newApproverAccountID: number, - accountID: number, - email: string, - policy: OnyxEntry, - hasViolations: boolean, - isASAPSubmitBetaEnabled: boolean, - reportCurrentNextStepDeprecated: OnyxEntry, - isTrackIntentUser: boolean | undefined, -) { - const takeControlReportAction = buildOptimisticChangeApproverReportAction(newApproverAccountID, accountID); +type AddReportApproverOptions = { + report: OnyxTypes.Report; + newApproverEmail: string; + newApproverAccountID: number; + accountID: number; + email: string; + policy: OnyxEntry; + hasViolations: boolean; + isASAPSubmitBetaEnabled: boolean; + reportCurrentNextStepDeprecated: OnyxEntry; + isTrackIntentUser: boolean | undefined; + translate: LocalizedTranslate; +}; + +function addReportApprover({ + report, + newApproverEmail, + newApproverAccountID, + accountID, + email, + policy, + hasViolations, + isASAPSubmitBetaEnabled, + reportCurrentNextStepDeprecated, + isTrackIntentUser, + translate, +}: AddReportApproverOptions) { + const takeControlReportAction = buildOptimisticChangeApproverReportAction(newApproverAccountID, accountID, translate); // buildOptimisticNextStep is used in parallel const optimisticNextStepDeprecated = buildNextStepNew({ diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 452a22da784d..2feaa8f17865 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -52,6 +52,7 @@ type EditTaskAssigneeOptions = { assigneeAccountID?: number | null; assigneeChatReport?: OnyxEntry; isOptimisticReport?: boolean; + translate: LocalizedTranslate; }; type OptimisticReport = Pick; @@ -788,9 +789,10 @@ function editTaskAssignee({ assigneeAccountID = 0, assigneeChatReport, isOptimisticReport, + translate, }: EditTaskAssigneeOptions) { // Create the EditedReportAction on the task - const editTaskReportAction = ReportUtils.buildOptimisticChangedTaskAssigneeReportAction(assigneeAccountID ?? CONST.DEFAULT_NUMBER_ID, currentUserAccountID, delegateEmail); + const editTaskReportAction = ReportUtils.buildOptimisticChangedTaskAssigneeReportAction(assigneeAccountID ?? CONST.DEFAULT_NUMBER_ID, currentUserAccountID, delegateEmail, translate); const reportName = report.reportName?.trim(); let assigneeChatReportOnyxData; diff --git a/src/pages/DynamicReportChangeApproverPage.tsx b/src/pages/DynamicReportChangeApproverPage.tsx index 866df5337ada..55499fe3dc20 100644 --- a/src/pages/DynamicReportChangeApproverPage.tsx +++ b/src/pages/DynamicReportChangeApproverPage.tsx @@ -89,9 +89,9 @@ function DynamicReportChangeApproverPage({report, policy, isLoadingReportData}: Navigation.navigate(ROUTES.REPORT_CHANGE_APPROVER_ADD_APPROVER.getRoute(report.reportID)); return; } - assignReportToMe(report, currentUserDetails.accountID, currentUserDetails.email ?? '', policy, hasViolations, isASAPSubmitBetaEnabled, reportNextStep, isTrackIntentUser); + assignReportToMe(report, currentUserDetails.accountID, currentUserDetails.email ?? '', policy, hasViolations, isASAPSubmitBetaEnabled, reportNextStep, isTrackIntentUser, translate); Navigation.dismissToPreviousRHP(); - }, [selectedApproverType, report, currentUserDetails.accountID, currentUserDetails.email, policy, hasViolations, isASAPSubmitBetaEnabled, reportNextStep, isTrackIntentUser]); + }, [selectedApproverType, report, currentUserDetails.accountID, currentUserDetails.email, policy, hasViolations, isASAPSubmitBetaEnabled, reportNextStep, isTrackIntentUser, translate]); const approverTypes = useMemo(() => { const data: Array> = [ diff --git a/src/pages/ReportAddApproverPage.tsx b/src/pages/ReportAddApproverPage.tsx index d53219ba6663..14c4fdab8154 100644 --- a/src/pages/ReportAddApproverPage.tsx +++ b/src/pages/ReportAddApproverPage.tsx @@ -101,18 +101,19 @@ function ReportAddApproverPage({report, isLoadingReportData, policy}: ReportAddA return; } startWithLoading(() => { - addReportApprover( + addReportApprover({ report, - selectedApproverEmail, - Number(employeeAccountID), - currentUserDetails.accountID, - currentUserDetails.email ?? '', + newApproverEmail: selectedApproverEmail, + newApproverAccountID: Number(employeeAccountID), + accountID: currentUserDetails.accountID, + email: currentUserDetails.email ?? '', policy, hasViolations, isASAPSubmitBetaEnabled, - reportNextStep, + reportCurrentNextStepDeprecated: reportNextStep, isTrackIntentUser, - ); + translate, + }); Navigation.dismissToPreviousRHP(); }); }; diff --git a/src/pages/Search/SearchAddApproverPage.tsx b/src/pages/Search/SearchAddApproverPage.tsx index 02261cfd94a1..495cb6d48ec4 100644 --- a/src/pages/Search/SearchAddApproverPage.tsx +++ b/src/pages/Search/SearchAddApproverPage.tsx @@ -140,18 +140,19 @@ function SearchAddApproverPage() { const hasViolations = hasViolationsReportUtils(report.reportID, transactionViolations, currentUserDetails.accountID, currentUserDetails.email ?? ''); const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${selectedReport.reportID}`]; - addReportApprover( + addReportApprover({ report, - selectedApproverEmail, - Number(employeeAccountID), - currentUserDetails.accountID, - currentUserDetails.email ?? '', + newApproverEmail: selectedApproverEmail, + newApproverAccountID: Number(employeeAccountID), + accountID: currentUserDetails.accountID, + email: currentUserDetails.email ?? '', policy, hasViolations, isASAPSubmitBetaEnabled, - reportNextStep, + reportCurrentNextStepDeprecated: reportNextStep, isTrackIntentUser, - ); + translate, + }); } // Note: This clears both reports and transactions diff --git a/src/pages/Search/SearchChangeApproverPage.tsx b/src/pages/Search/SearchChangeApproverPage.tsx index 9a02523439cd..a0b937528f55 100644 --- a/src/pages/Search/SearchChangeApproverPage.tsx +++ b/src/pages/Search/SearchChangeApproverPage.tsx @@ -175,7 +175,17 @@ function SearchChangeApproverPage() { if (report.managerID !== currentUserDetails.accountID) { const hasViolations = hasViolationsReportUtils(report.reportID, transactionViolations, currentUserDetails.accountID, currentUserDetails.email ?? ''); const reportNextStep = allReportNextSteps?.[`${ONYXKEYS.COLLECTION.NEXT_STEP}${selectedReport.reportID}`]; - assignReportToMe(report, currentUserDetails.accountID, currentUserDetails.email ?? '', policy, hasViolations, isASAPSubmitBetaEnabled, reportNextStep, isTrackIntentUser); + assignReportToMe( + report, + currentUserDetails.accountID, + currentUserDetails.email ?? '', + policy, + hasViolations, + isASAPSubmitBetaEnabled, + reportNextStep, + isTrackIntentUser, + translate, + ); } } diff --git a/src/pages/tasks/DynamicTaskAssigneeSelectorModal.tsx b/src/pages/tasks/DynamicTaskAssigneeSelectorModal.tsx index 11d9219c691b..ecff18c79fcd 100644 --- a/src/pages/tasks/DynamicTaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/DynamicTaskAssigneeSelectorModal.tsx @@ -176,6 +176,7 @@ function DynamicTaskAssigneeSelectorModal() { assigneeAccountID: option?.accountID, assigneeChatReport, isOptimisticReport, + translate, }); } Navigation.goBack(backPath); diff --git a/tests/actions/TaskTest.ts b/tests/actions/TaskTest.ts index 2895d9473ec5..8541fa05bc40 100644 --- a/tests/actions/TaskTest.ts +++ b/tests/actions/TaskTest.ts @@ -1384,6 +1384,7 @@ describe('actions/Task', () => { hasOutstandingChildTask: false, delegateEmail: DELEGATE_EMAIL, assigneeAccountID: ASSIGNEE_ACCOUNT_ID, + translate: translateLocal, }); const calls = mockWrite.mock.calls; @@ -1414,6 +1415,7 @@ describe('actions/Task', () => { hasOutstandingChildTask: false, delegateEmail: undefined, assigneeAccountID: ASSIGNEE_ACCOUNT_ID, + translate: translateLocal, }); const calls = mockWrite.mock.calls; diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 1c92c0a8e44b..91370ac9b024 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -33,6 +33,8 @@ import { buildOptimisticApprovedReportAction, buildOptimisticCancelPaymentReportAction, buildOptimisticCardAssignedReportAction, + buildOptimisticChangeApproverReportAction, + buildOptimisticChangedTaskAssigneeReportAction, buildOptimisticChatReport, buildOptimisticClosedReportAction, buildOptimisticCreatedReportAction, @@ -19938,6 +19940,54 @@ describe('ReportUtils', () => { }); }); + describe('buildOptimisticChangedTaskAssigneeReportAction', () => { + it('resolves the assignee display name through the injected translate function', async () => { + // A nameless assignee falls back to the "hidden" copy, which is produced by the injected translate + const hiddenAssigneeAccountID = 445566; + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { + [hiddenAssigneeAccountID]: {accountID: hiddenAssigneeAccountID, login: '', displayName: ''}, + }); + await waitForBatchedUpdates(); + + const translateWithMarker: LocalizedTranslate = (path, ...parameters) => (path === 'common.hidden' ? 'HiddenAssigneeMarker' : translateLocal(path, ...parameters)); + + const action = buildOptimisticChangedTaskAssigneeReportAction(hiddenAssigneeAccountID, currentUserAccountID, undefined, translateWithMarker); + + // The message text resolves the assignee through the provided translate, proving the param drives output + const [message] = Array.isArray(action.message) ? action.message : []; + expect(message?.text).toBe('assigned to HiddenAssigneeMarker'); + expect(action.actionName).toBe(CONST.REPORT.ACTIONS.TYPE.TASK_EDITED); + expect(action.actorAccountID).toBe(currentUserAccountID); + }); + }); + + describe('buildOptimisticChangeApproverReportAction', () => { + it('resolves the new approver display name through the injected translate function', async () => { + // A nameless manager falls back to the "hidden" copy, which is produced by the injected translate + const hiddenManagerAccountID = 445577; + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { + [hiddenManagerAccountID]: {accountID: hiddenManagerAccountID, login: '', displayName: ''}, + }); + await waitForBatchedUpdates(); + + const translateWithMarker: LocalizedTranslate = (path, ...parameters) => (path === 'common.hidden' ? 'HiddenApproverMarker' : translateLocal(path, ...parameters)); + + const action = buildOptimisticChangeApproverReportAction(hiddenManagerAccountID, currentUserAccountID, translateWithMarker); + + // The message text resolves the manager through the provided translate, proving the param drives output + const [message] = Array.isArray(action.message) ? action.message : []; + expect(message?.text).toBe('changed the approver to HiddenApproverMarker'); + // The actor differs from the new approver, so this is a reroute rather than taking control + expect(action.actionName).toBe(CONST.REPORT.ACTIONS.TYPE.REROUTE); + }); + + it('marks the action as TAKE_CONTROL when the actor assigns themselves', () => { + const action = buildOptimisticChangeApproverReportAction(currentUserAccountID, currentUserAccountID, translateLocal); + + expect(action.actionName).toBe(CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL); + }); + }); + describe('buildOptimisticCancelPaymentReportAction', () => { it('should set actorAccountID to the provided currentUserAccountID', () => { const customAccountID = 77;