diff --git a/src/components/ReportActionItem/TaskAction.js b/src/components/ReportActionItem/TaskAction.js index f30d8c3908de..d79bb6f78b93 100644 --- a/src/components/ReportActionItem/TaskAction.js +++ b/src/components/ReportActionItem/TaskAction.js @@ -3,8 +3,8 @@ import React from 'react'; import {View} from 'react-native'; import Text from '@components/Text'; import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import * as TaskUtils from '@libs/TaskUtils'; import useThemeStyles from '@styles/useThemeStyles'; -import * as Task from '@userActions/Task'; const propTypes = { /** Name of the reportAction action */ @@ -22,7 +22,7 @@ function TaskAction(props) { return ( <> - {Task.getTaskReportActionMessage(props.actionName, props.taskReportID, false)} + {TaskUtils.getTaskReportActionMessage(props.actionName)} ); diff --git a/src/components/ReportActionItem/TaskPreview.js b/src/components/ReportActionItem/TaskPreview.js index 4e405098a2ea..b48559e237a8 100644 --- a/src/components/ReportActionItem/TaskPreview.js +++ b/src/components/ReportActionItem/TaskPreview.js @@ -21,6 +21,7 @@ import getButtonState from '@libs/getButtonState'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; +import * as TaskUtils from '@libs/TaskUtils'; import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; import * as StyleUtils from '@styles/StyleUtils'; import useThemeStyles from '@styles/useThemeStyles'; @@ -83,7 +84,7 @@ function TaskPreview(props) { const isTaskCompleted = !_.isEmpty(props.taskReport) ? props.taskReport.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.taskReport.statusNum === CONST.REPORT.STATUS.APPROVED : props.action.childStateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.action.childStatusNum === CONST.REPORT.STATUS.APPROVED; - const taskTitle = props.taskReport.reportName || props.action.childReportName; + const taskTitle = TaskUtils.getTaskTitle(props.taskReportID, props.action.childReportName); const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(props.taskReport) || props.action.childManagerAccountID; const assigneeLogin = lodashGet(personalDetails, [taskAssigneeAccountID, 'login'], ''); const assigneeDisplayName = lodashGet(personalDetails, [taskAssigneeAccountID, 'displayName'], ''); diff --git a/src/languages/en.ts b/src/languages/en.ts index 7deb38b47e28..5294f2c420e2 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -62,6 +62,7 @@ import type { SplitAmountParams, StepCounterParams, TagSelectionParams, + TaskCreatedActionParams, ThreadRequestReportNameParams, ThreadSentMoneyReportNameParams, ToValidateLoginParams, @@ -1662,6 +1663,7 @@ export default { assignee: 'Assignee', completed: 'Completed', messages: { + created: ({title}: TaskCreatedActionParams) => `task for ${title}`, completed: 'marked as complete', canceled: 'deleted task', reopened: 'marked as incomplete', diff --git a/src/languages/es.ts b/src/languages/es.ts index b52975496e08..45e518a25fb6 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -62,6 +62,7 @@ import type { SplitAmountParams, StepCounterParams, TagSelectionParams, + TaskCreatedActionParams, ThreadRequestReportNameParams, ThreadSentMoneyReportNameParams, ToValidateLoginParams, @@ -1686,6 +1687,7 @@ export default { assignee: 'Usuario asignado', completed: 'Completada', messages: { + created: ({title}: TaskCreatedActionParams) => `tarea para ${title}`, completed: 'marcada como completa', canceled: 'tarea eliminado', reopened: 'marcada como incompleta', diff --git a/src/languages/types.ts b/src/languages/types.ts index a012ebdfb95b..0851174d9ed4 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -203,6 +203,8 @@ type TagSelectionParams = {tagName: string}; type WalletProgramParams = {walletProgram: string}; +type TaskCreatedActionParams = {title: string}; + /* Translation Object types */ // eslint-disable-next-line @typescript-eslint/no-explicit-any type TranslationBaseValue = string | string[] | ((...args: any[]) => string); @@ -321,4 +323,5 @@ export type { SetTheDistanceParams, UpdatedTheDistanceParams, WalletProgramParams, + TaskCreatedActionParams, }; diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index c616587c3983..19ce8abb526b 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -18,6 +18,7 @@ import Permissions from './Permissions'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as ReportActionUtils from './ReportActionsUtils'; import * as ReportUtils from './ReportUtils'; +import * as TaskUtils from './TaskUtils'; import * as TransactionUtils from './TransactionUtils'; import * as UserUtils from './UserUtils'; @@ -410,6 +411,8 @@ function getLastMessageTextForReport(report) { lastActionName === CONST.REPORT.ACTIONS.TYPE.TASKCANCELLED ) { lastMessageTextFromReport = lodashGet(lastReportAction, 'message[0].text', ''); + } else if (ReportActionUtils.isCreatedTaskReportAction(lastReportAction)) { + lastMessageTextFromReport = TaskUtils.getTaskCreatedMessage(lastReportAction); } else { lastMessageTextFromReport = report ? report.lastMessageText || '' : ''; } diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index ff9486159947..8418d8a1c3f1 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -10,7 +10,6 @@ import * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import Policy from '@src/types/onyx/Policy'; import Report from '@src/types/onyx/Report'; import ReportAction, {ReportActions} from '@src/types/onyx/ReportAction'; -import * as Task from './actions/Task'; import * as CollectionUtils from './CollectionUtils'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as Localize from './Localize'; @@ -18,6 +17,7 @@ import * as OptionsListUtils from './OptionsListUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; import * as ReportUtils from './ReportUtils'; +import * as TaskUtils from './TaskUtils'; import * as UserUtils from './UserUtils'; const visibleReportActionItems: ReportActions = {}; @@ -365,7 +365,7 @@ function getOptionData( const newName = lastAction?.originalMessage?.newName ?? ''; result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName}); } else if (ReportActionsUtils.isTaskAction(lastAction)) { - result.alternateText = Task.getTaskReportActionMessage(lastAction.actionName, report.reportID, false); + result.alternateText = TaskUtils.getTaskReportActionMessage(lastAction.actionName); } else if ( lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.REMOVE_FROM_ROOM || diff --git a/src/libs/TaskUtils.ts b/src/libs/TaskUtils.ts new file mode 100644 index 000000000000..3026e33edc8c --- /dev/null +++ b/src/libs/TaskUtils.ts @@ -0,0 +1,51 @@ +import Onyx, {OnyxEntry} from 'react-native-onyx'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import {Report} from '@src/types/onyx'; +import ReportAction from '@src/types/onyx/ReportAction'; +import * as CollectionUtils from './CollectionUtils'; +import * as Localize from './Localize'; + +const allReports: Record = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + callback: (report, key) => { + if (!key || !report) { + return; + } + const reportID = CollectionUtils.extractCollectionItemID(key); + allReports[reportID] = report; + }, +}); + +/** + * Given the Task reportAction name, return the appropriate message to be displayed and copied to clipboard. + */ +function getTaskReportActionMessage(actionName: string): string { + switch (actionName) { + case CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED: + return Localize.translateLocal('task.messages.completed'); + case CONST.REPORT.ACTIONS.TYPE.TASKCANCELLED: + return Localize.translateLocal('task.messages.canceled'); + case CONST.REPORT.ACTIONS.TYPE.TASKREOPENED: + return Localize.translateLocal('task.messages.reopened'); + default: + return Localize.translateLocal('task.task'); + } +} + +function getTaskTitle(taskReportID: string, fallbackTitle = ''): string { + const taskReport = allReports[taskReportID] ?? {}; + // We need to check for reportID, not just reportName, because when a receiver opens the task for the first time, + // an optimistic report is created with the only property – reportName: 'Chat report', + // and it will be displayed as the task title without checking for reportID to be present. + return Object.hasOwn(taskReport, 'reportID') && taskReport.reportName ? taskReport.reportName : fallbackTitle; +} + +function getTaskCreatedMessage(reportAction: OnyxEntry) { + const taskReportID = reportAction?.childReportID ?? ''; + const taskTitle = getTaskTitle(taskReportID, reportAction?.childReportName); + return Localize.translateLocal('task.messages.created', {title: taskTitle}); +} + +export {getTaskReportActionMessage, getTaskTitle, getTaskCreatedMessage}; diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index bf816d0a62a7..e5037d250d2e 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -6,7 +6,6 @@ import * as API from '@libs/API'; import DateUtils from '@libs/DateUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; -import * as Localize from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; @@ -906,35 +905,6 @@ function clearTaskErrors(reportID) { }); } -/** - * @param {string} actionName - * @param {string} reportID - * @param {boolean} isCreateTaskAction - * @returns {string} - */ -function getTaskReportActionMessage(actionName, reportID, isCreateTaskAction) { - const report = ReportUtils.getReport(reportID); - if (isCreateTaskAction) { - return `task for ${report.reportName}`; - } - let taskStatusText = ''; - switch (actionName) { - case CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED: - taskStatusText = Localize.translateLocal('task.messages.completed'); - break; - case CONST.REPORT.ACTIONS.TYPE.TASKCANCELLED: - taskStatusText = Localize.translateLocal('task.messages.canceled'); - break; - case CONST.REPORT.ACTIONS.TYPE.TASKREOPENED: - taskStatusText = Localize.translateLocal('task.messages.reopened'); - break; - default: - taskStatusText = Localize.translateLocal('task.task'); - } - - return `${taskStatusText}`; -} - export { createTaskAndNavigate, editTask, @@ -956,5 +926,4 @@ export { getTaskAssigneeAccountID, clearTaskErrors, canModifyTask, - getTaskReportActionMessage, }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 4f35926c5957..0736b60cafdf 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -16,6 +16,7 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import * as TaskUtils from '@libs/TaskUtils'; import * as Download from '@userActions/Download'; import * as Report from '@userActions/Report'; import * as Task from '@userActions/Task'; @@ -258,15 +259,13 @@ export default [ type === CONTEXT_MENU_TYPES.REPORT_ACTION && !ReportActionsUtils.isReportActionAttachment(reportAction) && !ReportActionsUtils.isMessageDeleted(reportAction), // If return value is true, we switch the `text` and `icon` on - // `ContextMenuItem` with `successText` and `successIcon` which will fallback to + // `ContextMenuItem` with `successText` and `successIcon` which will fall back to // the `text` and `icon` onPress: (closePopover, {reportAction, selection}) => { const isTaskAction = ReportActionsUtils.isTaskAction(reportAction); - const isCreateTaskAction = ReportActionsUtils.isCreatedTaskReportAction(reportAction); const isReportPreviewAction = ReportActionsUtils.isReportPreviewAction(reportAction); const message = _.last(lodashGet(reportAction, 'message', [{}])); - const reportID = lodashGet(reportAction, 'originalMessage.taskReportID', '').toString(); - const messageHtml = isTaskAction || isCreateTaskAction ? Task.getTaskReportActionMessage(reportAction.actionName, reportID, isCreateTaskAction) : lodashGet(message, 'html', ''); + const messageHtml = isTaskAction ? Task.getTaskReportActionMessage(reportAction) : lodashGet(message, 'html', ''); const isAttachment = ReportActionsUtils.isReportActionAttachment(reportAction); if (!isAttachment) { @@ -281,6 +280,9 @@ export default [ } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { const displayMessage = ReportUtils.getIOUReportActionDisplayMessage(reportAction); Clipboard.setString(displayMessage); + } else if (ReportActionsUtils.isCreatedTaskReportAction(reportAction)) { + const taskPreviewMessage = TaskUtils.getTaskCreatedMessage(reportAction); + Clipboard.setString(taskPreviewMessage); } else if (ReportActionsUtils.isChannelLogMemberAction(reportAction)) { const logMessage = ReportUtils.getChannelLogMemberMessage(reportAction); Clipboard.setString(logMessage);