diff --git a/src/components/TaskHeader.js b/src/components/TaskHeader.js index 001ed2b10bdd..c9852a8cfcbf 100644 --- a/src/components/TaskHeader.js +++ b/src/components/TaskHeader.js @@ -2,6 +2,7 @@ import React, {useEffect} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; import reportPropTypes from '../pages/reportPropTypes'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import * as ReportUtils from '../libs/ReportUtils'; @@ -22,6 +23,7 @@ import Button from './Button'; import * as TaskUtils from '../libs/actions/Task'; import * as UserUtils from '../libs/UserUtils'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; +import ONYXKEYS from '../ONYXKEYS'; const propTypes = { /** The report currently being looked at */ @@ -30,13 +32,25 @@ const propTypes = { /** Personal details so we can get the ones for the report participants */ personalDetails: PropTypes.objectOf(participantPropTypes).isRequired, + /** Current user session */ + session: PropTypes.shape({ + accountID: PropTypes.number, + }), + ...withLocalizePropTypes, }; +const defaultProps = { + session: { + accountID: 0, + }, +}; + function TaskHeader(props) { const title = ReportUtils.getReportName(props.report); - const assigneeName = ReportUtils.getDisplayNameForParticipant(props.report.managerID); - const assigneeAvatar = UserUtils.getAvatar(lodashGet(props.personalDetails, [props.report.managerID, 'avatar']), props.report.managerID); + const assigneeAccountID = TaskUtils.getTaskAssigneeAccountID(props.report); + const assigneeName = ReportUtils.getDisplayNameForParticipant(assigneeAccountID); + const assigneeAvatar = UserUtils.getAvatar(lodashGet(props.personalDetails, [assigneeAccountID, 'avatar']), assigneeAccountID); const isOpen = props.report.stateNum === CONST.REPORT.STATE_NUM.OPEN && props.report.statusNum === CONST.REPORT.STATUS.OPEN; const isCompleted = ReportUtils.isTaskCompleted(props.report); @@ -59,7 +73,7 @@ function TaskHeader(props) { > - {props.report.managerID && props.report.managerID > 0 && ( + {assigneeAccountID && assigneeAccountID > 0 && ( <> TaskUtils.completeTask(props.report.reportID, title)} @@ -123,6 +137,15 @@ function TaskHeader(props) { } TaskHeader.propTypes = propTypes; +TaskHeader.defaultProps = defaultProps; TaskHeader.displayName = 'TaskHeader'; -export default compose(withWindowDimensions, withLocalize)(TaskHeader); +export default compose( + withWindowDimensions, + withLocalize, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + }), +)(TaskHeader); diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index b5cdefa115d0..f57084c9f0e0 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -65,7 +65,7 @@ function hasCommentThread(reportAction) { } /** - * Returns the parentReportAction if the given report is a thread. + * Returns the parentReportAction if the given report is a thread/task. * * @param {Object} report * @returns {Object} diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 4003ba8002f0..c31f1617349d 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -10,6 +10,8 @@ import ROUTES from '../../ROUTES'; import CONST from '../../CONST'; import DateUtils from '../DateUtils'; import * as UserUtils from '../UserUtils'; +import * as PersonalDetailsUtils from '../PersonalDetailsUtils'; +import * as ReportActionsUtils from '../ReportActionsUtils'; /** * Clears out the task info from the store @@ -627,6 +629,47 @@ function dismissModalAndClearOutTaskInfo() { clearOutTaskInfo(); } +/** + * Returns Task assignee accountID + * + * @param {Object} taskReport + * @returns {Number|null} + */ +function getTaskAssigneeAccountID(taskReport) { + if (!taskReport) { + return null; + } + + if (taskReport.managerID) { + return taskReport.managerID; + } + + const reportAction = ReportActionsUtils.getParentReportAction(taskReport); + const childManagerEmail = lodashGet(reportAction, 'childManagerEmail', ''); + return PersonalDetailsUtils.getAccountIDsByLogins([childManagerEmail])[0]; +} + +/** + * Returns Task owner accountID + * + * @param {Object} taskReport + * @returns {Number|null} + */ +function getTaskOwnerAccountID(taskReport) { + return lodashGet(taskReport, 'ownerAccountID', null); +} + +/** + * Check if current user is either task assignee or task owner + * + * @param {Object} taskReport + * @param {Number} sessionAccountID + * @returns {Boolean} + */ +function isTaskAssigneeOrTaskOwner(taskReport, sessionAccountID) { + return sessionAccountID === getTaskOwnerAccountID(taskReport) || sessionAccountID === getTaskAssigneeAccountID(taskReport); +} + export { createTaskAndNavigate, editTaskAndNavigate, @@ -646,4 +689,6 @@ export { cancelTask, isTaskCanceled, dismissModalAndClearOutTaskInfo, + getTaskAssigneeAccountID, + isTaskAssigneeOrTaskOwner, }; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index b12733f64ef8..15ae1d2c64ec 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -51,6 +51,11 @@ const propTypes = { guideCalendarLink: PropTypes.string, }), + /** Current user session */ + session: PropTypes.shape({ + accountID: PropTypes.number, + }), + /** The report actions from the parent report */ // TO DO: Replace with HOC https://github.com/Expensify/App/issues/18769. // eslint-disable-next-line react/no-unused-prop-types @@ -68,6 +73,9 @@ const defaultProps = { guideCalendarLink: null, }, parentReport: {}, + session: { + accountID: 0, + }, }; function HeaderView(props) { @@ -91,7 +99,8 @@ function HeaderView(props) { const shouldShowCallButton = (isConcierge && guideCalendarLink) || (!isAutomatedExpensifyAccount && !isTaskReport); const threeDotMenuItems = []; if (isTaskReport) { - if (props.report.stateNum === CONST.REPORT.STATE_NUM.OPEN && props.report.statusNum === CONST.REPORT.STATUS.OPEN) { + const isTaskAssigneeOrTaskOwner = Task.isTaskAssigneeOrTaskOwner(props.report, props.session.accountID); + if (props.report.stateNum === CONST.REPORT.STATE_NUM.OPEN && props.report.statusNum === CONST.REPORT.STATUS.OPEN && isTaskAssigneeOrTaskOwner) { threeDotMenuItems.push({ icon: Expensicons.Checkmark, text: props.translate('newTaskPage.markAsDone'), @@ -100,7 +109,7 @@ function HeaderView(props) { } // Task is marked as completed - if (props.report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.report.statusNum === CONST.REPORT.STATUS.APPROVED) { + if (props.report.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.report.statusNum === CONST.REPORT.STATUS.APPROVED && isTaskAssigneeOrTaskOwner) { threeDotMenuItems.push({ icon: Expensicons.Checkmark, text: props.translate('newTaskPage.markAsIncomplete'), @@ -109,7 +118,7 @@ function HeaderView(props) { } // Task is not closed - if (props.report.stateNum !== CONST.REPORT.STATE_NUM.SUBMITTED && props.report.statusNum !== CONST.REPORT.STATUS.CLOSED) { + if (props.report.stateNum !== CONST.REPORT.STATE_NUM.SUBMITTED && props.report.statusNum !== CONST.REPORT.STATUS.CLOSED && isTaskAssigneeOrTaskOwner) { threeDotMenuItems.push({ icon: Expensicons.Trashcan, text: props.translate('common.cancel'), @@ -258,5 +267,8 @@ export default compose( parentReport: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID || report.reportID}`, }, + session: { + key: ONYXKEYS.SESSION, + }, }), )(HeaderView);