Skip to content

Commit d4ad6e3

Browse files
committed
tweaks to improve UX
1 parent 65f1d40 commit d4ad6e3

File tree

12 files changed

+217
-112
lines changed

12 files changed

+217
-112
lines changed

src/client/stylesheets/core/_header.scss

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,26 @@
55
.app-header {
66
border-bottom-color: $app-light-grey;
77
}
8+
9+
.app-width-container--wide {
10+
background-color: #f3f2f1;
11+
}
12+
13+
.manage-account-links {
14+
display: block;
15+
float: right;
16+
list-style-type: none;
17+
margin: 18px 0;
18+
19+
> li {
20+
display: inline;
21+
margin-bottom: 0;
22+
padding: 0 5px;
23+
text-align: right;
24+
border-right: 1px solid #000;
25+
26+
&:last-child {
27+
border-right: none;
28+
}
29+
}
30+
}

src/server/common/helpers/auth/defra-id.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,40 @@ const defraId = {
5151
token: oidcConf.token_endpoint,
5252
scope: ['openid', 'offline_access'],
5353
profile: async function (credentials, params) {
54+
server.logger.info('auth: Defra ID profile received')
55+
5456
// Decode JWT and extract user profile
5557
const payload = jwt.token.decode(credentials.token).decoded.payload
58+
const userId = payload.sub
5659
const displayName = getDisplayName(payload)
60+
const logoutUrl = oidcConf.end_session_endpoint
61+
const relationships =
62+
payload.relationships?.map((relationship) => {
63+
const [relationshipId, organisationId, organisationName] =
64+
relationship.split(':')
65+
66+
return {
67+
id: relationshipId,
68+
orgId: organisationId,
69+
orgName: organisationName?.trim(),
70+
isCurrent: payload.currentRelationshipId === relationshipId
71+
}
72+
}) ?? []
73+
const currentRelationship =
74+
relationships?.find(({ isCurrent }) => isCurrent) ?? null
75+
76+
server.app.defraId = {
77+
currentRelationship,
78+
logoutUrl,
79+
relationships,
80+
user: {
81+
id: userId,
82+
name: displayName
83+
}
84+
}
5785

5886
credentials.profile = {
59-
id: payload.sub,
87+
id: userId,
6088
correlationId: payload.correlationId,
6189
sessionId: payload.sessionId,
6290
contactId: payload.contactId,
@@ -75,7 +103,7 @@ const defraId = {
75103
roles: payload.roles,
76104
idToken: params.id_token,
77105
tokenUrl: oidcConf.token_endpoint,
78-
logoutUrl: oidcConf.end_session_endpoint
106+
logoutUrl
79107
}
80108
}
81109
},

src/server/common/helpers/auth/fetch.js

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -20,69 +20,81 @@ function getOrganisationLinkHref(id, redirectUrl) {
2020
}
2121

2222
export async function fetchWithAuthInterception(url, request, h) {
23-
const { data, response } = await fetchWithAuthHeader(url, request)
23+
request.logger.info({ url }, 'auth: fetchWithAuthInterception')
2424

25-
if (!response.ok) {
26-
throw Boom.unauthorized()
27-
}
28-
29-
if (data.action === 'link-organisations') {
30-
const { path: redirectUrl } = request
31-
const { defraId, isCurrentOrganisationLinked, organisations } = data
32-
const hasManyOrganisations = organisations.length > 1
33-
const entityName = hasManyOrganisations ? 'organisations' : 'organisation'
34-
const shouldShowTableOfUnlinkedOrganisations =
35-
hasManyOrganisations && !isCurrentOrganisationLinked
36-
const otherRelationships = defraId.otherRelationships.map(
37-
({ defraIdOrgName, defraIdRelationshipId }) => [
38-
{ text: defraIdOrgName },
39-
{
40-
html: `<a href="http://localhost:3200/cdp-defra-id-stub/register/${defraId.userId}/relationship/${defraIdRelationshipId}/current">Switch</a>`
41-
}
42-
]
43-
)
25+
try {
26+
const { data, response } = await fetchWithAuthHeader(url, request)
4427

45-
const commonTemplateData = {
46-
defraIdOrgName: defraId.orgName,
47-
entityName,
48-
isCurrentOrganisationLinked,
49-
otherRelationships,
50-
shouldShowTableOfUnlinkedOrganisations
28+
if (!response.ok) {
29+
throw Boom.unauthorized()
5130
}
5231

53-
const templateData = shouldShowTableOfUnlinkedOrganisations
54-
? {
55-
...commonTemplateData,
56-
organisations: organisations.map(({ name, orgId, id }) => [
57-
{ text: name ?? 'data missing' },
58-
{ text: orgId ?? 'data missing' },
59-
{ text: id ?? 'data missing' },
60-
{
61-
html: `<a href="${getOrganisationLinkHref(id, redirectUrl)}">Link</a>`
32+
if (data.action === 'link-organisations') {
33+
const { path: redirectUrl } = request
34+
const { defraId, isCurrentOrganisationLinked, organisations } = data
35+
const hasManyOrganisations = organisations.length > 1
36+
const entityName = hasManyOrganisations ? 'organisations' : 'organisation'
37+
const shouldShowTableOfUnlinkedOrganisations =
38+
hasManyOrganisations && !isCurrentOrganisationLinked
39+
const otherRelationships = defraId.otherRelationships.map(
40+
({ defraIdOrgName, defraIdRelationshipId }) => [
41+
{ text: defraIdOrgName },
42+
{
43+
html: `<a href="http://localhost:3200/cdp-defra-id-stub/register/${defraId.userId}/relationship/${defraIdRelationshipId}/current">Switch</a>`
44+
}
45+
]
46+
)
47+
48+
const commonTemplateData = {
49+
defraIdOrgName: defraId.orgName,
50+
entityName,
51+
isCurrentOrganisationLinked,
52+
otherRelationships,
53+
shouldShowTableOfUnlinkedOrganisations
54+
}
55+
56+
const templateData = shouldShowTableOfUnlinkedOrganisations
57+
? {
58+
...commonTemplateData,
59+
organisations: organisations.map(({ name, orgId, id }) => [
60+
{ text: name ?? 'data missing' },
61+
{ text: orgId ?? 'data missing' },
62+
{ text: id ?? 'data missing' },
63+
{
64+
html: `<a href="${getOrganisationLinkHref(id, redirectUrl)}">Link</a>`
65+
}
66+
])
67+
}
68+
: {
69+
...commonTemplateData,
70+
organisation: {
71+
name: organisations[0].name,
72+
orgId: organisations[0].orgId,
73+
id: organisations[0].id,
74+
linkHref: getOrganisationLinkHref(
75+
organisations[0].id,
76+
redirectUrl
77+
),
78+
addHref: `http://localhost:3200/cdp-defra-id-stub/register/${defraId.userId}/relationship`
6279
}
63-
])
64-
}
65-
: {
66-
...commonTemplateData,
67-
organisation: {
68-
name: organisations[0].name,
69-
orgId: organisations[0].orgId,
70-
id: organisations[0].id,
71-
linkHref: getOrganisationLinkHref(organisations[0].id, redirectUrl),
72-
addHref: `http://localhost:3200/cdp-defra-id-stub/register/${defraId.userId}/relationship`
7380
}
74-
}
7581

76-
return {
77-
data,
78-
response,
79-
view: h.view('organisation/link-options', {
80-
pageTitle: 'Link Organisation',
81-
heading: 'Link Organisation',
82-
...templateData
83-
})
82+
return {
83+
data,
84+
response,
85+
view: h.view('organisation/link-options', {
86+
pageTitle: 'Link Organisation',
87+
heading: 'Link Organisation',
88+
defraId: request.server.app.defraId,
89+
...templateData
90+
})
91+
}
8492
}
85-
}
8693

87-
return { data, response }
94+
return { data, response }
95+
} catch (error) {
96+
request.logger.error(error, 'auth: fetchWithAuthInterception')
97+
98+
throw error
99+
}
88100
}

src/server/common/helpers/auth/user-session.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { getUserSession } from './get-user-session.js'
1212
async function removeUserSession(request) {
1313
await dropUserSession(request)
1414
request.cookieAuth.clear()
15+
request.server.app.defraId = null
1516
}
1617

1718
/**

src/server/common/helpers/errors.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export function catchAll(request, h) {
4040
.view('error/index', {
4141
pageTitle: errorMessage,
4242
heading: statusCode,
43-
message: errorMessage
43+
message: errorMessage,
44+
defraId: request.server.app.defraId
4445
})
4546
.code(statusCode)
4647
}

src/server/common/templates/layouts/page.njk

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,40 @@
3232
serviceUrl: "/",
3333
navigation: navigation
3434
}) }}
35+
{% if isDefraIdEnabled %}
36+
<div class="menu">
37+
<div class="govuk-grid-row govuk-width-container app-width-container--wide">
38+
<div class="govuk-grid-column-full">
39+
<ul class="manage-account-links govuk-!-padding-0">
40+
{% if defraId.currentRelationship %}
41+
<li class="govuk-body-s">
42+
<a href="http://localhost:3200/cdp-defra-id-stub/register/{{ defraId.user.id }}" class="govuk-link">{{ defraId.user.name }}</a>
43+
</li>
44+
<li class="govuk-body-s">
45+
{% if defraId.relationships.length > 1 %}
46+
<a
47+
class="govuk-link"
48+
href="http://localhost:3200/cdp-defra-id-stub/register/{{ defraId.user.id }}/relationship/{{ defraId.currentRelationship.id }}/current"
49+
>
50+
{{ defraId.currentRelationship.orgName }}
51+
</a>
52+
{% else %}
53+
{{ defraId.currentRelationship.orgName }}
54+
{% endif %}
55+
</li>
56+
<li class="govuk-body-s">
57+
<a href="/logout" class="govuk-link">Sign out</a>
58+
</li>
59+
{% else %}
60+
<li class="govuk-body-s">
61+
<a href="/login" class="govuk-link">Sign in</a>
62+
</li>
63+
{% endif %}
64+
</ul>
65+
</div>
66+
</div>
67+
</div>
68+
{% endif %}
3569
{% endblock %}
3670

3771
{% block pageTitle %}

src/server/home/controller.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
1+
import { config } from '#config/config.js'
2+
import { fetchWithAuthInterception } from '#server/common/helpers/auth/fetch.js'
3+
14
/**
25
* A GDS styled example home page controller.
36
* Provided as an example, remove or modify as required.
47
* @satisfies {Partial<ServerRoute>}
58
*/
69
export const homeController = {
7-
handler(_request, h) {
10+
async handler(request, h) {
11+
if (request.auth.isAuthenticated) {
12+
const { currentRelationship } = request.server.app.defraId
13+
const baseUrl = config.get('eprBackendUrl')
14+
const url = `${baseUrl}/v1/organisations/${currentRelationship.orgId}/defra-id-org-id`
15+
const { data, view } = await fetchWithAuthInterception(url, request, h)
16+
17+
if (view) {
18+
return view
19+
}
20+
21+
if (data.length === 1) {
22+
return h.redirect(`/organisations/${data[0].id}`)
23+
}
24+
25+
// @todo: handle multiple matches by DefraIdOrgId
26+
}
27+
828
return h.view('home/index', {
929
pageTitle: 'Home',
10-
heading: 'Home'
30+
heading: 'Home',
31+
defraId: request.server.app.defraId
1132
})
1233
}
1334
}

src/server/home/index.njk

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,29 @@
66
<div class="govuk-body" data-testid="app-page-body">
77
<h1 class="govuk-heading-l">Sites</h1>
88

9-
{% if isDefraIdEnabled %}
10-
{% if authedUser and authedUser.displayName %}
11-
<div class="govuk-panel govuk-panel--confirmation" style="background-color: #f3f2f1; border: 2px solid #1d70b8;">
12-
<div class="govuk-panel__body" style="color: #0b0c0c;">
13-
Welcome, <strong>{{ authedUser.displayName }}</strong>
14-
</div>
9+
{% if isDefraIdEnabled and authedUser and authedUser.displayName %}
10+
<div class="govuk-panel govuk-panel--confirmation" style="background-color: #f3f2f1; border: 2px solid #1d70b8;">
11+
<div class="govuk-panel__body" style="color: #0b0c0c;">
12+
Welcome, <strong>{{ authedUser.displayName }}</strong>
1513
</div>
16-
<p class="govuk-body">
17-
<a href="/logout" class="govuk-link">Sign out</a>
18-
</p>
19-
<details class="govuk-details">
20-
<summary class="govuk-details__summary">
21-
<span class="govuk-details__summary-text">
22-
View your account details
23-
</span>
24-
</summary>
25-
<div class="govuk-details__text">
26-
<dl class="govuk-summary-list">
27-
{% for key, value in authedUser %}
28-
<div class="govuk-summary-list__row">
29-
<dt class="govuk-summary-list__key">{{ key }}</dt>
30-
<dd class="govuk-summary-list__value"><code>{{ value }}</code></dd>
31-
</div>
32-
{% endfor %}
33-
</dl>
34-
</div>
35-
</details>
36-
{% else %}
37-
<p class="govuk-body">
38-
Welcome, guest!
39-
</p>
40-
<p class="govuk-body">
41-
You can <a id="login-link" href="/login" class="govuk-link">sign in</a> to access your account.
42-
</p>
43-
{% endif %}
14+
</div>
15+
<details class="govuk-details">
16+
<summary class="govuk-details__summary">
17+
<span class="govuk-details__summary-text">
18+
View your account details
19+
</span>
20+
</summary>
21+
<div class="govuk-details__text">
22+
<dl class="govuk-summary-list">
23+
{% for key, value in authedUser %}
24+
<div class="govuk-summary-list__row">
25+
<dt class="govuk-summary-list__key">{{ key }}</dt>
26+
<dd class="govuk-summary-list__value"><code>{{ value }}</code></dd>
27+
</div>
28+
{% endfor %}
29+
</dl>
30+
</div>
31+
</details>
4432
{% endif %}
4533

4634
<h2 class="govuk-heading-m">Test</h2>
@@ -50,12 +38,18 @@
5038
<p>
5139
<a href="/organisations/6507f1f77bcf86cd79943921" class="govuk-link">Plastic Exporters</a>
5240
</p>
41+
<p>
42+
<a href="/organisations/6507f1f77bcf86cd79943931" class="govuk-link">Future Green Trust</a>
43+
</p>
5344
<p>
5445
<a href="/organisations/6507f1f77bcf86cd79943901/registrations/6507f1f77bcf86cd79943902" class="govuk-link">ACME ltd: Glass</a>
5546
</p>
5647
<p>
5748
<a href="/organisations/6507f1f77bcf86cd79943921/registrations/6507f1f77bcf86cd79943922" class="govuk-link">Plastic Exporters: Plastic</a>
5849
</p>
50+
<p>
51+
<a href="/organisations/6507f1f77bcf86cd79943931/registrations/6507f1f77bcf86cd79943932" class="govuk-link">Future Green Trust: Steel</a>
52+
</p>
5953
</div>
6054
</div>
6155
</div>

0 commit comments

Comments
 (0)