diff --git a/src/client/components/Dashboard/my-tasks/MyTasksTable.jsx b/src/client/components/Dashboard/my-tasks/MyTasksTable.jsx
index 83ae73e8c0e..d425cb6aa56 100644
--- a/src/client/components/Dashboard/my-tasks/MyTasksTable.jsx
+++ b/src/client/components/Dashboard/my-tasks/MyTasksTable.jsx
@@ -6,6 +6,7 @@ import styled from 'styled-components'
import { formatMediumDate } from '../../../utils/date'
import urls from '../../../../lib/urls'
+import { STATUS } from '../../../modules/Tasks/TaskForm/constants'
export const transformAdvisersListItem = (advisers) => {
return advisers.map((adviser, index) => (
@@ -46,7 +47,11 @@ const rows = ({ results }) => {
{transformAdvisersListItem(task.advisers)}
- {task.archived ? 'Completed' : 'Active'}
+ {task.archived
+ ? 'Deleted'
+ : task.status == STATUS.COMPLETED
+ ? 'Completed'
+ : 'Active'}
))
diff --git a/src/client/components/Dashboard/my-tasks/state.js b/src/client/components/Dashboard/my-tasks/state.js
index ca8fc912ba5..2eeb537e32d 100644
--- a/src/client/components/Dashboard/my-tasks/state.js
+++ b/src/client/components/Dashboard/my-tasks/state.js
@@ -9,6 +9,7 @@ import {
ME_OTHERS_LIST_OPTIONS,
SHOW_ALL_OPTION,
} from './constants'
+import { STATUS } from '../../../modules/Tasks/TaskForm/constants'
export const ID = 'getMyTasks'
export const TASK_GET_MY_TASKS = 'TASK_GET_MY_TASKS'
@@ -30,9 +31,10 @@ const sortbyMapping = {
company_ascending: 'company.name:asc',
project_ascending: 'investment_project.name:asc',
}
+
const statusMapping = {
- active: { archived: false },
- completed: { archived: true },
+ active: { status: STATUS.ACTIVE },
+ completed: { status: STATUS.COMPLETED },
}
export const state2props = ({ router, ...state }) => {
@@ -50,6 +52,7 @@ export const state2props = ({ router, ...state }) => {
sortby: 'due_date:asc',
company: undefined,
project: undefined,
+ status: undefined,
}
const assignedToMapping = {
diff --git a/src/client/components/Dashboard/my-tasks/tasks.js b/src/client/components/Dashboard/my-tasks/tasks.js
index 934964dab15..3f2008948b4 100644
--- a/src/client/components/Dashboard/my-tasks/tasks.js
+++ b/src/client/components/Dashboard/my-tasks/tasks.js
@@ -6,10 +6,11 @@ export const getMyTasks = ({
not_created_by,
advisers,
not_advisers,
- archived,
+ archived = false,
sortby = 'due_date:asc',
company,
project,
+ status,
}) =>
apiProxyAxios
.post('/v4/search/task', {
@@ -24,5 +25,6 @@ export const getMyTasks = ({
sortby,
company,
investment_project: project,
+ status,
})
.then(({ data }) => data)
diff --git a/src/client/modules/Tasks/TaskDetails/TaskButtons.jsx b/src/client/modules/Tasks/TaskDetails/TaskButtons.jsx
index 7a8297bc47e..3874c6f993c 100644
--- a/src/client/modules/Tasks/TaskDetails/TaskButtons.jsx
+++ b/src/client/modules/Tasks/TaskDetails/TaskButtons.jsx
@@ -8,8 +8,13 @@ import styled from 'styled-components'
import { Form } from '../../../components'
import urls from '../../../../lib/urls'
-import { TASK_ARCHIVE_TASK, buttonState2props } from './state'
-import { GREY_3, TEXT_COLOUR } from '../../../utils/colours'
+import {
+ TASK_DELETE,
+ TASK_SAVE_STATUS_COMPLETE,
+ buttonState2props,
+} from './state'
+import { GREY_3, RED, TEXT_COLOUR } from '../../../utils/colours'
+import { STATUS } from '../TaskForm/constants'
const ButtonWrapper = styled.div`
min-height: 71px;
@@ -21,28 +26,33 @@ const ButtonWrapper = styled.div`
}
`
+const DeleteTaskWrapper = styled.div`
+ * {
+ margin-left: ${SPACING.SCALE_1};
+ }
+`
+
export const TaskButtons = ({ task, returnUrl }) => (
<>
- {!task.archived && (
+ {!task.archived && task.status == STATUS.ACTIVE && (
+ />
)}
- {!task.archived && (
+ {!task.archived && task.status == STATUS.ACTIVE && (
+
+ {!task.archived && (
+
+
+ )}
+
{
const { taskId } = useParams()
-
const taskTitle = task ? task.title : ''
- const archivedTag = task?.archived && (
+ const statusTag = task?.status == STATUS.COMPLETED && (
COMPLETED
)
+ const archivedTag = task?.archived && (
+
+ DELETED
+
+ )
+ const subheading =
+ archivedTag || statusTag ? (
+ <>
+ {archivedTag} {statusTag}
+ >
+ ) : (
+ ''
+ )
return (
{
diff --git a/src/client/modules/Tasks/TaskDetails/tasks.js b/src/client/modules/Tasks/TaskDetails/tasks.js
index bdc42df5337..cec59dddd00 100644
--- a/src/client/modules/Tasks/TaskDetails/tasks.js
+++ b/src/client/modules/Tasks/TaskDetails/tasks.js
@@ -3,5 +3,11 @@ import { apiProxyAxios } from '../../../components/Task/utils'
export const getTaskDetail = (id) =>
apiProxyAxios.get(`v4/task/${id}`).then(({ data }) => data)
-export const archiveTask = ({ taskId }) =>
- apiProxyAxios.post(`/v4/task/${taskId}/archive`, { reason: 'completed' })
+export const saveTaskStatusComplete = ({ taskId }) =>
+ apiProxyAxios.post(`/v4/task/${taskId}/status-complete`)
+
+export const saveTaskStatusActive = ({ taskId }) =>
+ apiProxyAxios.post(`/v4/task/${taskId}/status-active`)
+
+export const deleteTask = ({ taskId }) =>
+ apiProxyAxios.post(`/v4/task/${taskId}/archive`, { reason: 'deleted' })
diff --git a/src/client/modules/Tasks/TaskForm/constants.js b/src/client/modules/Tasks/TaskForm/constants.js
index 7d29c5543d9..353540de4ad 100644
--- a/src/client/modules/Tasks/TaskForm/constants.js
+++ b/src/client/modules/Tasks/TaskForm/constants.js
@@ -9,3 +9,10 @@ export const OPTIONS = {
{ label: 'Someone else', value: OPTION_SOMEONE_ELSE },
],
}
+
+const STATUS_ACTIVE = 'active'
+const STATUS_COMPLETED = 'complete'
+export const STATUS = {
+ ACTIVE: STATUS_ACTIVE,
+ COMPLETED: STATUS_COMPLETED,
+}
diff --git a/src/client/tasks.js b/src/client/tasks.js
index b0fa0fae350..0e8d2db07b6 100644
--- a/src/client/tasks.js
+++ b/src/client/tasks.js
@@ -418,10 +418,17 @@ import { getOmisCompanies } from './modules/Omis/CreateOrder/CompanySelect/tasks
import { TASK_CREATE_ORDER } from './modules/Omis/CreateOrder/state'
import { createOrder } from './modules/Omis/CreateOrder/tasks'
-import { archiveTask, getTaskDetail } from './modules/Tasks/TaskDetails/tasks'
import {
- TASK_ARCHIVE_TASK,
+ saveTaskStatusActive,
+ saveTaskStatusComplete,
+ getTaskDetail,
+ deleteTask,
+} from './modules/Tasks/TaskDetails/tasks'
+import {
+ TASK_SAVE_STATUS_ACTIVE,
+ TASK_SAVE_STATUS_COMPLETE,
TASK_GET_TASK_DETAILS,
+ TASK_DELETE,
} from './modules/Tasks/TaskDetails/state'
import { saveTaskDetail } from './modules/Tasks/TaskForm/tasks'
import { TASK_SAVE_TASK_DETAILS } from './modules/Tasks/TaskForm/state'
@@ -647,7 +654,9 @@ export const tasks = {
[TASK_EDIT_OMIS_INTERNAL_INFORMATION]: updateOrder,
[TASK_GET_TASK_DETAILS]: getTaskDetail,
[TASK_GET_INVESTMENT_PROJECT]: investmentProjectTasks.getInvestmentProject,
- [TASK_ARCHIVE_TASK]: archiveTask,
+ [TASK_SAVE_STATUS_COMPLETE]: saveTaskStatusComplete,
+ [TASK_SAVE_STATUS_ACTIVE]: saveTaskStatusActive,
+ [TASK_DELETE]: deleteTask,
[TASK_RECONCILE_OMIS_PAYMENT]: savePayment,
[TASK_SAVE_TASK_DETAILS]: saveTaskDetail,
[TASK_EDIT_INVOICE_DETAILS]: updateOrder,
diff --git a/src/lib/urls.js b/src/lib/urls.js
index aee9c57c254..96a2104fe5a 100644
--- a/src/lib/urls.js
+++ b/src/lib/urls.js
@@ -730,5 +730,9 @@ module.exports = {
createInteraction: url('/tasks/create?interactionId=', ':interactionId'),
createCopyTask: url('/tasks/create?copyTaskId=', ':copyTaskId'),
edit: url('/tasks', '/:taskId/edit'),
+ statusComplete: url('/tasks', '/:taskId/status-complete'),
+ statusActive: url('/tasks', '/:taskId/status-active'),
+ archive: url('/tasks', '/:taskId/archive'),
+ unarchive: url('/tasks', '/:taskId/unarchive'),
},
}
diff --git a/test/a11y/cypress/config/urlTestExclusions.js b/test/a11y/cypress/config/urlTestExclusions.js
index 325877de390..6e7f370df02 100644
--- a/test/a11y/cypress/config/urlTestExclusions.js
+++ b/test/a11y/cypress/config/urlTestExclusions.js
@@ -131,6 +131,11 @@ export const urlTestExclusions = [
{ url: '/investments/projects/:investmentId/propositions/:propositionId' },
{ url: '/companies/:companyId/hierarchies/ghq/:globalHqId/add' },
{ url: '/companies/:companyId/hierarchies/ghq/remove' },
+ // API calls with redirect
+ { url: '/tasks/:taskId/status-complete' },
+ { url: '/tasks/:taskId/status-active' },
+ { url: '/tasks/:taskId/archive' },
+ { url: '/tasks/:taskId/unarchive' },
// 501 errors
{ url: '/api-proxy/v4/company/:companyId/export-win' },
{ url: '/investments/projects/:projectId/edit-ukcompany/:companyId' },
diff --git a/test/component/cypress/specs/Dashboard/MyTasks/MyTasksTable.cy.jsx b/test/component/cypress/specs/Dashboard/MyTasks/MyTasksTable.cy.jsx
index 0cbe2ee1723..da1ffee57b6 100644
--- a/test/component/cypress/specs/Dashboard/MyTasks/MyTasksTable.cy.jsx
+++ b/test/component/cypress/specs/Dashboard/MyTasks/MyTasksTable.cy.jsx
@@ -13,6 +13,7 @@ import urls from '../../../../../../src/lib/urls'
import { keysToSnakeCase } from '../../../../../functional/cypress/fakers/utils'
import Provider from '../../provider'
+import { STATUS } from '../../../../../../src/client/modules/Tasks/TaskForm/constants'
describe('My Tasks on the Dashboard', () => {
const Component = (props) => (
@@ -24,7 +25,7 @@ describe('My Tasks on the Dashboard', () => {
)
// Create 3 tasks of which one is Archived
const myTasksList = taskWithInvestmentProjectListFaker()
- myTasksList[1].archived = true
+ myTasksList[1].status = STATUS.COMPLETED
const myTaskResults = myTasksList.map((task) => keysToSnakeCase(task))
const myTasks = {
diff --git a/test/component/cypress/specs/Tasks/TaskDetails/TaskButtons.cy.jsx b/test/component/cypress/specs/Tasks/TaskDetails/TaskButtons.cy.jsx
index 54081835a3d..c102ae07c2c 100644
--- a/test/component/cypress/specs/Tasks/TaskDetails/TaskButtons.cy.jsx
+++ b/test/component/cypress/specs/Tasks/TaskDetails/TaskButtons.cy.jsx
@@ -44,18 +44,75 @@ describe('Task buttons', () => {
})
context('When a task is completed', () => {
- const task = taskWithInvestmentProjectFaker({ archived: true })
+ const task = taskWithInvestmentProjectFaker({ status: 'complete' })
beforeEach(() => {
cy.mount()
})
it('should not show the Mark as complete button', () => {
+ cy.get('[data-test="submit-button"]').should(
+ 'not.contain.text',
+ 'Mark as complete'
+ )
+ })
+
+ it('should not show the Edit link', () => {
+ cy.get('[data-test="edit-form-button"]').should('not.exist')
+ })
+
+ it('should show the Create similar task link', () => {
+ cy.get('[data-test="create-similar-task-button"]').should('exist')
+ })
+
+ it('should show the Back link to dashboard when no return url exists', () => {
+ assertLink('task-back-link', urls.dashboard.myTasks())
+ })
+ })
+
+ context('When a task is not archived/deleted', () => {
+ const task = taskWithInvestmentProjectFaker()
+
+ beforeEach(() => {
+ cy.mount()
+ })
+
+ it('should show the Delete task button', () => {
+ cy.get('[data-test="submit-button"]').should(
+ 'contain.text',
+ 'Delete task'
+ )
+ })
+
+ it('should show the Edit link with expected url', () => {
+ assertLink('edit-form-button', urls.tasks.edit(task.id))
+ })
+
+ it('should show the Create similar task button with expected url', () => {
+ assertLink(
+ 'create-similar-task-button',
+ urls.tasks.createCopyTask(task.id)
+ )
+ })
+
+ it('should show the Back link to dashboard when no return url exists', () => {
+ assertLink('task-back-link', urls.dashboard.myTasks())
+ })
+ })
+
+ context('When a task is archived/deleted', () => {
+ const task = taskWithInvestmentProjectFaker({ archived: true })
+
+ beforeEach(() => {
+ cy.mount()
+ })
+
+ it('should not show the Delete task nor Mark as complete buttons', () => {
cy.get('[data-test="edit-form-button"]').should('not.exist')
})
it('should not show the Edit link', () => {
- cy.get('[data-test="submit-button"]').should('not.exist')
+ cy.get('[data-test="edit-form-button"]').should('not.exist')
})
it('should show the Create similar task link', () => {
diff --git a/test/functional/cypress/fakers/task.js b/test/functional/cypress/fakers/task.js
index c7e5ad75c99..a006931708e 100644
--- a/test/functional/cypress/fakers/task.js
+++ b/test/functional/cypress/fakers/task.js
@@ -4,6 +4,7 @@ import { pick } from 'lodash'
import { listFaker } from './utils'
import { companyFaker } from './companies'
import { interactionFaker } from './interactions'
+import { STATUS } from '../../../../src/client/modules/Tasks/TaskForm/constants'
const basicAdviserFaker = (overrides = {}) => ({
name: faker.person.fullName(),
@@ -29,6 +30,7 @@ const taskFaker = (overrides = {}) => ({
modifiedBy: basicAdviserFaker(),
modifiedOn: faker.date.past().toISOString(),
createdOn: faker.date.past().toISOString(),
+ status: STATUS.ACTIVE,
...overrides,
})
diff --git a/test/functional/cypress/specs/dashboard/filter-spec.js b/test/functional/cypress/specs/dashboard/filter-spec.js
index b4bb74d1ac7..5e3c203fba0 100644
--- a/test/functional/cypress/specs/dashboard/filter-spec.js
+++ b/test/functional/cypress/specs/dashboard/filter-spec.js
@@ -23,6 +23,7 @@ describe('Task filters', () => {
offset: 0,
adviser: [myAdviserId],
sortby: 'due_date:asc',
+ archived: false,
}
//Remap investment_project property to investmentProject so it displays in the Task List UI properly
TaskList[0].investment_project = TaskList[0].investmentProject
@@ -234,6 +235,7 @@ describe('Task filters', () => {
offset: 0,
adviser: [myAdviserId],
sortby: sortBy,
+ archived: false,
})
assertListItems({ length: 1 })
})
@@ -300,24 +302,29 @@ describe('Task filters', () => {
})
it('should filter active status from the url', () => {
- testFilterFromUrl(element, 'status=active', { archived: false }, 'Active')
+ testFilterFromUrl(
+ element,
+ 'status=active',
+ { status: 'active' },
+ 'Active'
+ )
})
it('should filter completed status from the url', () => {
testFilterFromUrl(
element,
'status=completed',
- { archived: true },
+ { status: 'complete' },
'Completed'
)
})
it('should filter active status from user input', () => {
- testFilterFromUserInput(element, { archived: false }, 'Active')
+ testFilterFromUserInput(element, { status: 'active' }, 'Active')
})
it('should filter completed status from user input', () => {
- testFilterFromUserInput(element, { archived: true }, 'Completed')
+ testFilterFromUserInput(element, { status: 'complete' }, 'Completed')
})
})
diff --git a/test/functional/cypress/specs/tasks/details-spec.js b/test/functional/cypress/specs/tasks/details-spec.js
index 654ed75d0bf..a718214d6b9 100644
--- a/test/functional/cypress/specs/tasks/details-spec.js
+++ b/test/functional/cypress/specs/tasks/details-spec.js
@@ -12,10 +12,12 @@ import {
} from '../../support/assertions'
import { clickButton } from '../../support/actions'
import interactionsListFaker from '../../fakers/interactions'
+import { STATUS } from '../../../../../src/client/modules/Tasks/TaskForm/constants'
describe('View details for a generic task', () => {
- const genericTaskCompleted = taskFaker({ archived: true })
- const genericTaskNotCompleteTask = taskFaker({ archived: false })
+ const genericTaskCompleted = taskFaker({ status: STATUS.COMPLETED })
+ const genericTaskNotCompleteTask = taskFaker({ status: STATUS.ACTIVE })
+ const generticTaskArchived = taskFaker({ archived: true })
context('When visiting a completed task details', () => {
beforeEach(() => {
@@ -43,6 +45,49 @@ describe('View details for a generic task', () => {
)
cy.get('[data-test="activity-kind-label"]').should('contain', 'COMPLETED')
+ cy.get('[data-test="activity-kind-label"]').should(
+ 'not.contain',
+ 'DELETED'
+ )
+ })
+
+ it('should display the summary table', () => {
+ assertSummaryTable({
+ dataTest: 'task-details-table',
+ })
+ })
+ })
+
+ context('When visiting an archived task details', () => {
+ beforeEach(() => {
+ cy.intercept(
+ 'GET',
+ `/api-proxy/v4/task/${generticTaskArchived.id}`,
+ generticTaskArchived
+ ).as('apiRequest')
+ cy.visit(tasks.details(generticTaskArchived.id))
+ cy.wait('@apiRequest')
+ })
+
+ it('should display the task title in the breadcrumbs', () => {
+ assertBreadcrumbs({
+ Home: dashboard.myTasks(),
+ [generticTaskArchived.title]: tasks.details(generticTaskArchived.id),
+ Task: null,
+ })
+ })
+
+ it('should display the title of the task and deleted tag', () => {
+ cy.get('[data-test="heading"]').should(
+ 'contain',
+ generticTaskArchived.title
+ )
+
+ cy.get('[data-test="activity-kind-label"]').should('contain', 'DELETED')
+ cy.get('[data-test="activity-kind-label"]').should(
+ 'not.contain',
+ 'COMPLETED'
+ )
})
it('should display the summary table', () => {
@@ -52,7 +97,7 @@ describe('View details for a generic task', () => {
})
})
- context('When visiting a not complete task details', () => {
+ context('When visiting a not complete not archived task details', () => {
beforeEach(() => {
cy.intercept(
'GET',
@@ -72,14 +117,25 @@ describe('View details for a generic task', () => {
cy.get('[data-test="activity-kind-label"]').should('not.exist')
})
- it('should redirect to the dashboard and show the Flash message after marking as complete', () => {
+ it('should redirect to the dashboard and show the Flash message after deleting', () => {
cy.intercept(
'POST',
`/api-proxy/v4/task/${genericTaskNotCompleteTask.id}/archive`,
{}
).as('postTaskArchiveApiRequest')
+ clickButton('Delete task')
+ assertPayload('@postTaskArchiveApiRequest', { reason: 'deleted' })
+ assertUrl(dashboard.myTasks())
+ })
+
+ it('should redirect to the dashboard and show the Flash message after marking as complete', () => {
+ cy.intercept(
+ 'POST',
+ `/api-proxy/v4/task/${genericTaskNotCompleteTask.id}/status-complete`,
+ {}
+ ).as('postTaskStatusCompleteApiRequest')
clickButton('Mark as complete')
- assertPayload('@postTaskArchiveApiRequest', { reason: 'completed' })
+ cy.wait('@postTaskStatusCompleteApiRequest')
assertUrl(dashboard.myTasks())
})
})
@@ -90,8 +146,8 @@ describe('View details for task that is assigned to an investment project', () =
archived: false,
})
- context('When visiting a not complete task details', () => {
- before(() => {
+ context('When visiting a not complete not archived task details', () => {
+ beforeEach(() => {
cy.intercept(
'GET',
`/api-proxy/v4/task/${investmentProjectTask.id}`,
@@ -102,13 +158,24 @@ describe('View details for task that is assigned to an investment project', () =
})
it('should redirect to the investment project and show the Flash message after marking as complete', () => {
+ cy.intercept(
+ 'POST',
+ `/api-proxy/v4/task/${investmentProjectTask.id}/status-complete`,
+ {}
+ ).as('postTaskStatusCompleteApiRequest')
+ clickButton('Mark as complete')
+ cy.wait('@postTaskStatusCompleteApiRequest')
+ assertUrl(dashboard.myTasks())
+ })
+
+ it('should redirect to the investment project and show the Flash message after deleting', () => {
cy.intercept(
'POST',
`/api-proxy/v4/task/${investmentProjectTask.id}/archive`,
{}
).as('postTaskArchiveApiRequest')
- clickButton('Mark as complete')
- assertPayload('@postTaskArchiveApiRequest', { reason: 'completed' })
+ clickButton('Delete task')
+ assertPayload('@postTaskArchiveApiRequest', { reason: 'deleted' })
assertUrl(dashboard.myTasks())
})
})
@@ -117,8 +184,8 @@ describe('View details for task that is assigned to an investment project', () =
describe('View details for task that is assigned to a company', () => {
const companyTask = taskWithCompanyFaker({ archived: false })
- context('When visiting a not complete task details', () => {
- before(() => {
+ context('When visiting a not complete not archived task details', () => {
+ beforeEach(() => {
cy.intercept(
'GET',
`/api-proxy/v4/task/${companyTask.id}`,
@@ -129,13 +196,24 @@ describe('View details for task that is assigned to a company', () => {
})
it('should redirect to the investment project and show the Flash message after marking as complete', () => {
+ cy.intercept(
+ 'POST',
+ `/api-proxy/v4/task/${companyTask.id}/status-complete`,
+ {}
+ ).as('postTaskStatusCompleteApiRequest')
+ clickButton('Mark as complete')
+ cy.wait('@postTaskStatusCompleteApiRequest')
+ assertUrl(dashboard.myTasks())
+ })
+
+ it('should redirect to the investment project and show the Flash message after deleting', () => {
cy.intercept(
'POST',
`/api-proxy/v4/task/${companyTask.id}/archive`,
{}
).as('postTaskArchiveApiRequest')
- clickButton('Mark as complete')
- assertPayload('@postTaskArchiveApiRequest', { reason: 'completed' })
+ clickButton('Delete task')
+ assertPayload('@postTaskArchiveApiRequest', { reason: 'deleted' })
assertUrl(dashboard.myTasks())
})
})