Skip to content

Commit

Permalink
Merge pull request #18747 from Expensify/arosiclair-cancel-task-action
Browse files Browse the repository at this point in the history
  • Loading branch information
thienlnam authored May 16, 2023
2 parents a5fc2e1 + c0377c4 commit fa372fc
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ const CONST = {
CLOSED: 'CLOSED',
CREATED: 'CREATED',
TASKEDITED: 'TASKEDITED',
TASKCANCELED: 'TASKCANCELED',
IOU: 'IOU',
RENAMED: 'RENAMED',
CHRONOSOOOLIST: 'CHRONOSOOOLIST',
Expand Down
3 changes: 3 additions & 0 deletions src/components/ReportActionItem/TaskAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ const TaskAction = (props) => {
case CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED:
messageLinkText = props.translate('task.messages.completed');
break;
case CONST.REPORT.ACTIONS.TYPE.TASKCANCELED:
messageLinkText = props.translate('task.messages.canceled');
break;
case CONST.REPORT.ACTIONS.TYPE.TASKREOPENED:
messageLinkText = props.translate('task.messages.reopened');
break;
Expand Down
1 change: 1 addition & 0 deletions src/components/ReportActionItem/TaskPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const TaskPreview = (props) => {
style={[styles.mr2]}
containerStyle={[styles.taskCheckbox]}
isChecked={isTaskCompleted}
disabled={TaskUtils.isTaskCanceled(props.taskReport)}
onPress={() => {
if (isTaskCompleted) {
TaskUtils.reopenTask(props.taskReportID, parentReportID, taskTitle);
Expand Down
1 change: 1 addition & 0 deletions src/components/TaskHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ function TaskHeader(props) {
) : (
<Button
success
isDisabled={TaskUtils.isTaskCanceled(props.report)}
medium
text={props.translate('newTaskPage.markAsDone')}
onPress={() => TaskUtils.completeTask(props.report.reportID, parentReportID, title)}
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,7 @@ export default {
completed: 'Completed',
messages: {
completed: 'Completed task',
canceled: 'Canceled task',
reopened: 'Reopened task',
},
},
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,7 @@ export default {
completed: 'Completada',
messages: {
completed: 'Tarea completada',
canceled: 'Tarea cancelada',
reopened: 'Tarea reabrir',
},
},
Expand Down
6 changes: 5 additions & 1 deletion src/libs/ReportActionsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,11 @@ function shouldReportActionBeVisible(reportAction, key) {
}

// Filter out any unsupported reportAction types
if (!_.has(CONST.REPORT.ACTIONS.TYPE, reportAction.actionName) && !_.contains(_.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), reportAction.actionName)) {
if (
!_.has(CONST.REPORT.ACTIONS.TYPE, reportAction.actionName) &&
!_.contains(_.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), reportAction.actionName) &&
!_.contains(_.values(CONST.REPORT.ACTIONS.TYPE.TASK), reportAction.actionName)
) {
return false;
}

Expand Down
69 changes: 68 additions & 1 deletion src/libs/actions/Task.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import * as ReportUtils from '../ReportUtils';
import * as Report from './Report';
import Navigation from '../Navigation/Navigation';
import ROUTES from '../../ROUTES';
import DateUtils from '../DateUtils';
import CONST from '../../CONST';
import DateUtils from '../DateUtils';

/**
* Clears out the task info from the store
Expand Down Expand Up @@ -502,6 +502,71 @@ function getShareDestination(reportID, reports, personalDetails) {
};
}

/**
* Cancels a task by setting the report state to SUBMITTED and status to CLOSED
* @param {string} taskReportID
* @param {string} parentReportID
* @param {string} taskTitle
* @param {number} originalStateNum
* @param {number} originalStatusNum
*/
function cancelTask(taskReportID, parentReportID, taskTitle, originalStateNum, originalStatusNum) {
const message = `Canceled task: ${taskTitle}`;
const optimisticCancelReportAction = ReportUtils.buildOptimisticTaskReportAction(taskReportID, CONST.REPORT.ACTIONS.TYPE.TASKCANCELED, message);
const optimisticReportActionID = optimisticCancelReportAction.reportActionID;

const optimisticData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`,
value: {
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
statusNum: CONST.REPORT.STATUS.CLOSED,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`,
value: {
lastVisibleActionCreated: optimisticCancelReportAction.created,
lastMessageText: message,
lastActorEmail: optimisticCancelReportAction.actorEmail,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`,
value: {
[optimisticReportActionID]: optimisticCancelReportAction,
},
},
];

const failureData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`,
value: {
stateNum: originalStateNum,
statusNum: originalStatusNum,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`,
value: {
[optimisticReportActionID]: null,
},
},
];

API.write('CancelTask', {taskReportID, optimisticReportActionID}, {optimisticData, failureData});
}

function isTaskCanceled(taskReport) {
return taskReport.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && taskReport.statusNum === CONST.REPORT.STATUS.CLOSED;
}

export {
createTaskAndNavigate,
editTaskAndNavigate,
Expand All @@ -517,4 +582,6 @@ export {
clearOutTaskInfoAndNavigate,
getAssignee,
getShareDestination,
cancelTask,
isTaskCanceled,
};
21 changes: 11 additions & 10 deletions src/pages/home/HeaderView.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import colors from '../../styles/colors';
import reportPropTypes from '../reportPropTypes';
import ONYXKEYS from '../../ONYXKEYS';
import ThreeDotsMenu from '../../components/ThreeDotsMenu';
import * as Task from '../../libs/actions/Task';
import reportActionPropTypes from './report/reportActionPropTypes';
import * as TaskUtils from '../../libs/actions/Task';

const propTypes = {
/** Toggles the navigationMenu open and closed */
Expand Down Expand Up @@ -86,15 +86,13 @@ const HeaderView = (props) => {
// We hide the button when we are chatting with an automated Expensify account since it's not possible to contact
// these users via alternative means. It is possible to request a call with Concierge so we leave the option for them.
const shouldShowCallButton = (isConcierge && guideCalendarLink) || (!isAutomatedExpensifyAccount && !isTaskReport);
const shouldShowThreeDotsButton = isTaskReport;
const threeDotMenuItems = [];

if (shouldShowThreeDotsButton) {
if (isTaskReport) {
if (props.report.stateNum === CONST.REPORT.STATE_NUM.OPEN && props.report.statusNum === CONST.REPORT.STATUS.OPEN) {
threeDotMenuItems.push({
icon: Expensicons.Checkmark,
text: props.translate('newTaskPage.markAsDone'),
onSelected: () => TaskUtils.completeTask(props.report.reportID, props.report.parentReportID, title),
onSelected: () => Task.completeTask(props.report.reportID, props.report.parentReportID, title),
});
}

Expand All @@ -103,7 +101,7 @@ const HeaderView = (props) => {
threeDotMenuItems.push({
icon: Expensicons.Checkmark,
text: props.translate('newTaskPage.markAsIncomplete'),
onSelected: () => TaskUtils.reopenTask(props.report.reportID, props.report.parentReportID, title),
onSelected: () => Task.reopenTask(props.report.reportID, props.report.parentReportID, title),
});
}

Expand All @@ -112,12 +110,11 @@ const HeaderView = (props) => {
threeDotMenuItems.push({
icon: Expensicons.Trashcan,
text: props.translate('common.cancel'),

// Implementing in https://github.com/Expensify/App/issues/16857
onSelected: () => {},
onSelected: () => Task.cancelTask(props.report.reportID, props.report.parentReportID, props.report.reportName, props.report.stateNum, props.report.statusNum),
});
}
}
const shouldShowThreeDotsButton = !!threeDotMenuItems.length;

const avatarTooltip = isChatRoom ? undefined : _.pluck(displayNamesWithTooltips, 'tooltip');
const shouldShowSubscript = isPolicyExpenseChat && !props.report.isOwnPolicyExpenseChat && !ReportUtils.isArchivedRoom(props.report) && !isTaskReport;
Expand Down Expand Up @@ -231,7 +228,11 @@ export default compose(
withOnyx({
account: {
key: ONYXKEYS.ACCOUNT,
selector: (account) => account && {guideCalendarLink: account.guideCalendarLink},
selector: (account) =>
account && {
guideCalendarLink: account.guideCalendarLink,
primaryLogin: account.primaryLogin,
},
},
parentReportActions: {
key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/report/ReportActionItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class ReportActionItem extends Component {
checkIfContextMenuActive={this.checkIfContextMenuActive}
/>
);
} else if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED) {
} else if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED || this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCANCELED) {
children = (
<TaskAction
taskReportID={this.props.action.originalMessage.taskReportID.toString()}
Expand Down

0 comments on commit fa372fc

Please sign in to comment.