-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Export project interactions
Sort by
functionality (#7500)
* Layout test scenarios - Sort export project interaction list Sort a default company export interaction list * Added test coverage for company export interaction * Added export interaction collection list test * Update sandbox server `/v4/export/:exportId` endpoint error response * Fix export interaction tab navigation failing test * Moved a constant functions declaration Is a best practice to declare constant functions in the beginning of the codebase before calling, in order the javascript interpreter can locate. This action being reverted and noted as part of flakiness/tech debt. * Use interaction `subject` rather than export `title` Amend the current implementation of export interaction list by using `subject` rather than export interaction `title` on the list because is already on the header and repetitive each details .
- Loading branch information
Showing
13 changed files
with
593 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import React from 'react' | ||
import styled from 'styled-components' | ||
import { useLocation } from 'react-router-dom' | ||
|
||
import ExportInteractionsList from './ExportInteractionsList' | ||
import ExportResource from '../../components/Resource/Export' | ||
import { DefaultLayout } from '../../components' | ||
import TabNav from '../../components/TabNav' | ||
import ExportDetails from './ExportDetails' | ||
import urls from '../../../lib/urls' | ||
|
||
const EXPORT_ID_REGEX = /\/export\/([^/]+)\// | ||
const EXPORT_ASPECT_REGEX = /\/([^/]+)$/ | ||
|
||
const StyledLink = styled('a')({ | ||
fontSize: 20, | ||
display: 'inline-block', | ||
fontFamily: 'Arial, sans-serif', | ||
marginTop: 8, | ||
marginBottom: 8, | ||
}) | ||
|
||
export const CompanyLink = (props) => ( | ||
<ExportResource.Inline {...props}> | ||
{({ company }) => ( | ||
<StyledLink | ||
data-test="export-company-link" | ||
href={urls.companies.detail(company.id)} | ||
> | ||
{company.name.toUpperCase()} | ||
</StyledLink> | ||
)} | ||
</ExportResource.Inline> | ||
) | ||
|
||
export const ExportProjectTitle = (props) => ( | ||
<ExportResource.Inline {...props}> | ||
{(exportProject) => exportProject.title} | ||
</ExportResource.Inline> | ||
) | ||
|
||
const Export = () => { | ||
const location = useLocation() | ||
const matchId = location.pathname.match(EXPORT_ID_REGEX) | ||
const exportId = matchId ? matchId[1] : null | ||
const matchAspect = location.pathname.match(EXPORT_ASPECT_REGEX) | ||
const aspect = matchAspect ? matchAspect[1] : null // aspect will be either 'details' or 'interactions' | ||
|
||
return ( | ||
<DefaultLayout | ||
superheading={<CompanyLink id={exportId} />} | ||
heading={<ExportProjectTitle id={exportId} />} | ||
pageTitle={`Export ${aspect}`} | ||
breadcrumbs={[ | ||
{ link: urls.exportPipeline.index(), text: 'Home' }, | ||
{ text: <ExportProjectTitle id={exportId} /> }, | ||
]} | ||
> | ||
<TabNav | ||
id="export-tab-nav" | ||
label="Export tab nav" | ||
layout="vertical" | ||
routed={true} | ||
tabs={{ | ||
[urls.exportPipeline.details(exportId)]: { | ||
label: 'Project details', | ||
content: <ExportDetails />, | ||
}, | ||
[urls.exportPipeline.interactions.index(exportId)]: { | ||
label: 'Interactions', | ||
content: <ExportInteractionsList exportId={exportId} />, | ||
}, | ||
}} | ||
/> | ||
</DefaultLayout> | ||
) | ||
} | ||
|
||
export default Export |
63 changes: 63 additions & 0 deletions
63
src/client/modules/ExportPipeline/ExportInteractionsList/index.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import React from 'react' | ||
|
||
import { LEVEL_SIZE } from '@govuk-react/constants' | ||
import { H2 } from 'govuk-react' | ||
|
||
import Interactions from '../../../components/Resource/Interactions' | ||
import { formatDate, DATE_FORMAT_FULL } from '../../../utils/date-utils' | ||
import { CollectionItem } from '../../../components' | ||
import urls from '../../../../lib/urls' | ||
import { SORT_OPTIONS_EXPORT_INTERACTION } from '../constants' | ||
|
||
const ExportInteractionsList = ({ interactions = [] }) => | ||
interactions.length === 0 ? null : ( | ||
<ul data-test="export-interactions-list"> | ||
{interactions.map((item) => ( | ||
<CollectionItem | ||
key={item.id} | ||
headingText={item.subject} | ||
headingUrl={urls.exportPipeline.interactions.details(item.id)} | ||
metadata={[ | ||
{ | ||
label: 'Date:', | ||
value: formatDate(item.date, DATE_FORMAT_FULL), | ||
}, | ||
{ | ||
label: 'Contact(s):', | ||
value: item.contacts.map(({ name }) => name).join(', '), | ||
}, | ||
{ | ||
label: 'Adviser(s):', | ||
value: item.dit_participants | ||
.map(({ adviser, team }) => `${adviser.name} - ${team.name}`) | ||
.join(', '), | ||
}, | ||
{ | ||
label: 'Service:', | ||
value: item.service.name, | ||
}, | ||
]} | ||
/> | ||
))} | ||
</ul> | ||
) | ||
|
||
export default ({ exportId }) => ( | ||
<> | ||
<H2 size={LEVEL_SIZE[3]}>Interactions</H2> | ||
<p> | ||
An interaction could be a meeting, call, email or another activity | ||
associated with this export. | ||
</p> | ||
<Interactions.Paginated | ||
id="export-interactions" | ||
heading="interactions" | ||
shouldPluralize={true} | ||
noResults="You don't have any export interactions." | ||
payload={{ company_export_id: exportId }} | ||
sortOptions={SORT_OPTIONS_EXPORT_INTERACTION} | ||
> | ||
{(page) => <ExportInteractionsList interactions={page} />} | ||
</Interactions.Paginated> | ||
</> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
170 changes: 170 additions & 0 deletions
170
test/component/cypress/specs/ExportPipeline/ExportInteractionsList.cy.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
import React from 'react' | ||
|
||
import ExportInteractionsList from '../../../../../src/client/modules/ExportPipeline/ExportInteractionsList' | ||
import { interactionFaker } from '../../../../functional/cypress/fakers/interactions' | ||
|
||
describe('ExportInteractionsList', () => { | ||
it('should render a list of export project interactions', () => { | ||
const exportProject = { | ||
id: '1', | ||
title: 'Baileys export to Brazil', | ||
} | ||
|
||
const interaction = { | ||
id: 123, | ||
date: '2024-12-23', | ||
contacts: [ | ||
{ | ||
name: 'James Brown', | ||
}, | ||
], | ||
dit_participants: [ | ||
{ | ||
adviser: { | ||
name: 'David Buffer', | ||
}, | ||
team: { | ||
name: 'Digital Data Hub - Live Service', | ||
}, | ||
}, | ||
], | ||
service: { | ||
name: 'Account management : General', | ||
}, | ||
subject: 'Video call meeting to Baileys', | ||
} | ||
|
||
const interactionList = [ | ||
interaction, | ||
interactionFaker(), | ||
interactionFaker(), | ||
] | ||
|
||
cy.mountWithProvider( | ||
<ExportInteractionsList exportId={exportProject.id} />, | ||
{ | ||
tasks: { | ||
Interactions: () => Promise.resolve(interactionList), | ||
Export: () => Promise.resolve(exportProject), | ||
}, | ||
} | ||
) | ||
|
||
cy.get('[data-test="export-interactions-list"]').should('exist') | ||
cy.get('[data-test="collection-item"]').as('collectionItems') | ||
cy.get('@collectionItems').eq(0).as('firstItem') | ||
|
||
cy.get('@collectionItems').should('have.length', 3) | ||
|
||
cy.get('@firstItem').within(() => { | ||
cy.get('h3 a') | ||
.should('have.text', 'Video call meeting to Baileys') | ||
.and('have.attr', 'href', '/export/123/interactions/details') | ||
|
||
const items = '[data-test="metadata-item"]' | ||
cy.get(items).should('have.length', 4) | ||
cy.get(items).eq(0).should('have.text', 'Date: 23 December 2024') | ||
cy.get(items).eq(1).should('have.text', 'Contact(s): James Brown') | ||
cy.get(items) | ||
.eq(2) | ||
.should( | ||
'have.text', | ||
'Adviser(s): David Buffer - Digital Data Hub - Live Service' | ||
) | ||
cy.get(items) | ||
.eq(3) | ||
.should('have.text', 'Service: Account management : General') | ||
}) | ||
}) | ||
|
||
it('should render a list of multiple contacts', () => { | ||
const interaction = { | ||
id: 224, | ||
date: '2024-12-23', | ||
contacts: [ | ||
{ | ||
name: 'James Brown', | ||
}, | ||
{ | ||
name: 'Jim Brown', | ||
}, | ||
{ | ||
name: 'Jude Brown', | ||
}, | ||
], | ||
dit_participants: [], | ||
service: { | ||
name: 'Account management : General', | ||
}, | ||
subject: 'Video call meeting to Baileys', | ||
} | ||
cy.mountWithProvider(<ExportInteractionsList />, { | ||
tasks: { | ||
Interactions: () => Promise.resolve([interaction]), | ||
}, | ||
}) | ||
|
||
cy.get('[data-test="metadata-item"]') | ||
.eq(1) | ||
.should('have.text', 'Contact(s): James Brown, Jim Brown, Jude Brown') | ||
}) | ||
|
||
it('should render a list of multiple advisers', () => { | ||
const interaction = { | ||
date: '2024-12-23', | ||
contacts: [], | ||
dit_participants: [ | ||
{ | ||
adviser: { | ||
name: 'James Brown', | ||
}, | ||
team: { | ||
name: 'British Water', | ||
}, | ||
}, | ||
{ | ||
adviser: { | ||
name: 'Jim Brown', | ||
}, | ||
team: { | ||
name: 'Cumbria LEP', | ||
}, | ||
}, | ||
{ | ||
adviser: { | ||
name: 'Jude Brown', | ||
}, | ||
team: { | ||
name: 'Doncaster Council', | ||
}, | ||
}, | ||
], | ||
service: { | ||
name: 'Account management : General', | ||
}, | ||
subject: 'Send email to Baileys', | ||
} | ||
cy.mountWithProvider(<ExportInteractionsList />, { | ||
tasks: { | ||
Interactions: () => Promise.resolve([interaction]), | ||
}, | ||
}) | ||
|
||
cy.get('[data-test="metadata-item"]') | ||
.eq(2) | ||
.should( | ||
'have.text', | ||
'Adviser(s): James Brown - British Water, Jim Brown - Cumbria LEP, Jude Brown - Doncaster Council' | ||
) | ||
}) | ||
|
||
it('should not render a list of export project interactions', () => { | ||
cy.mountWithProvider(<ExportInteractionsList />, { | ||
tasks: { | ||
Interactions: () => Promise.resolve([]), | ||
}, | ||
}) | ||
|
||
cy.get('[data-test="export-interactions-list"]').should('not.exist') | ||
}) | ||
}) |
Oops, something went wrong.