Skip to content

Commit

Permalink
Add feedback page
Browse files Browse the repository at this point in the history
Includes full form lifecycle with error validation and confirmation page
  • Loading branch information
NickColley committed Feb 14, 2019
1 parent 98a2dfe commit a2add05
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 0 deletions.
36 changes: 36 additions & 0 deletions app/__tests__/app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const expectedPages = [
'/examples/template-custom',
'/full-page-examples/bank-holidays',
'/full-page-examples/check-your-answers',
'/full-page-examples/feedback-page',
'/full-page-examples/service-manual-topic',
'/full-page-examples/start-page'
]
Expand Down Expand Up @@ -104,6 +105,41 @@ describe(`http://localhost:${PORT}`, () => {
})
})

describe('/full-page-examples/feedback-page', () => {
it('should not show errors if submit with no input', (done) => {
request.get({
url: `http://localhost:${PORT}/full-page-examples/feedback-page`
}, (err, res) => {
let $ = cheerio.load(res.body)

// Check the page responded correctly
expect(res.statusCode).toBe(200)
expect($.html()).toContain('Send your feedback to this service')

// Check that the error summary is not visible
let $errorSummary = $('[data-module="error-summary"]')
expect($errorSummary.length).toBeFalsy()
done(err)
})
})
it('should show errors if form is submitted with no input', (done) => {
request.post({
url: `http://localhost:${PORT}/full-page-examples/feedback-page`
}, (err, res) => {
let $ = cheerio.load(res.body)

// Check the page responded correctly
expect(res.statusCode).toBe(200)
expect($.html()).toContain('Send your feedback to this service')

// Check that the error summary is visible
let $errorSummary = $('[data-module="error-summary"]')
expect($errorSummary.length).toBeTruthy()
done(err)
})
})
})

describe('/examples/template-custom', () => {
const templatePath = '/examples/template-custom'

Expand Down
2 changes: 2 additions & 0 deletions app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ module.exports = (options) => {
})
})

require('./views/full-page-examples/feedback-page')(app)

app.get('/robots.txt', function (req, res) {
res.type('text/plain')
res.send('User-agent: *\nDisallow: /')
Expand Down
19 changes: 19 additions & 0 deletions app/views/full-page-examples/feedback-page/confirm.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{# This example is based of the live "Send your feedback to GOV.UK Verify" start page: https://www.signin.service.gov.uk/feedback #}
{% extends "_generic.njk" %}

{% from "panel/macro.njk" import govukPanel %}

{% set pageTitle = "Thank you for your feedback" %}
{% block pageTitle %}GOV.UK - {{ pageTitle }}{% endblock %}

{% set mainClasses = "govuk-main-wrapper--l" %}

{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
{{ govukPanel({
titleText: pageTitle
}) }}
</div>
</div>
{% endblock %}
76 changes: 76 additions & 0 deletions app/views/full-page-examples/feedback-page/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { body, validationResult } = require('express-validator/check')

// To make it easier to use in the view, might be nicer as a Nunjucks function
function getErrors (errorsInstance) {
if (errorsInstance.isEmpty()) {
return false
}
const errors = errorsInstance.array()
const formattedErrors = {}
errors.forEach(error => {
formattedErrors[error.param] = {
href: '#' + error.param,
value: error.value,
text: error.msg
}
})
return formattedErrors
}

module.exports = (app) => {
app.post(
'/full-page-examples/feedback-page',
[
body('what-were-you-trying-to-do')
.exists()
.not().isEmpty().withMessage('Enter what you were trying to do')
.isLength({ max: 3000 }).withMessage('What were you trying to do must be 3000 characters or less'),
body('detail')
.exists()
.not().isEmpty().withMessage('Enter details of your question, problem or feedback')
.isLength({ max: 3000 }).withMessage('Details of your question, problem or feedback must be 3000 characters or less'),
body('do-you-want-a-reply')
.exists()
.not().isEmpty().withMessage('Select yes if you want a reply'),
body('name')
.custom((value, { req: request }) => {
// See https://github.com/express-validator/express-validator/pull/658
const wantsReply = request.body['do-you-want-a-reply'] === 'yes'
if (!wantsReply) {
return true
}
if (!value) {
throw new Error('Enter your name')
}
return true
}),
body('email')
.custom((value, { req: request }) => {
// See https://github.com/express-validator/express-validator/pull/658
const wantsReply = request.body['do-you-want-a-reply'] === 'yes'
if (!wantsReply) {
return true
}
if (!value) {
throw new Error('Enter your email address')
}
if (!value.includes('@')) {
throw new Error('Enter an email address in the correct format, like [email protected]')
}
return true
})

],
(request, response) => {
const errors = getErrors(validationResult(request))
if (errors) {
return response.render('./full-page-examples/feedback-page/index', {
errors,
errorSummary: Object.values(errors),
values: request.body // In production this should sanitized.
})
}
response.render('./full-page-examples/feedback-page/confirm')
}
)
}
121 changes: 121 additions & 0 deletions app/views/full-page-examples/feedback-page/index.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{# This example is based of the live "Send your feedback to GOV.UK Verify" start page: https://www.signin.service.gov.uk/feedback #}
{% extends "_generic.njk" %}

{% from "radios/macro.njk" import govukRadios %}
{% from "input/macro.njk" import govukInput %}
{% from "character-count/macro.njk" import govukCharacterCount %}
{% from "button/macro.njk" import govukButton %}
{% from "error-summary/macro.njk" import govukErrorSummary %}

{% set pageTitle = "Send your feedback to this service" %}
{% block pageTitle %}GOV.UK - {{ pageTitle }}{% endblock %}

{% set mainClasses = "govuk-main-wrapper--l" %}

{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form method="post" novalidate>
{% if errorSummary.length > 0 %}
{{ govukErrorSummary({
titleText: "There is a problem",
errorList: errorSummary
}) }}
{% endif %}

<h1 class="govuk-heading-xl">{{ pageTitle }}</h1>

<p class="govuk-body">
Use this form to ask a question, report a problem or suggest an improvement this service can make.
</p>

<p class="govuk-body govuk-!-font-weight-bold">
Don't include any personal or financial information like your National Insurance number or credit card details.
</p>

{{ govukCharacterCount({
name: "what-were-you-trying-to-do",
id: "what-were-you-trying-to-do",
maxlength: 3000,
label: {
text: "What were you trying to do?"
},
value: values["what-were-you-trying-to-do"],
errorMessage: errors["what-were-you-trying-to-do"]
}) }}

{{ govukCharacterCount({
name: "detail",
id: "detail",
maxlength: 3000,
label: {
text: "Please provide details of your question, problem or feedback"
},
value: values["detail"],
errorMessage: errors["detail"]
}) }}

{% set yesHTML %}
<p class="govuk-body">Leave your details below if you'd like a response from this service.</p>

{{ govukInput({
id: "name",
name: "name",
label: {
text: "Name"
},
value: values["name"],
errorMessage: errors["name"]
}) }}

{{ govukInput({
id: "email",
name: "email",
type: "email",
label: {
text: "Email address"
},
hint: {
text: "We’ll only use this to reply to your message."
},
value: values["email"],
errorMessage: errors["email"]
}) }}

<p class="govuk-body govuk-!-margin-top-6">By sending this message, you consent to us using your information as detailed in the privacy notice.</p>
{% endset -%}

{{ govukRadios({
idPrefix: "do-you-want-a-reply",
name: "do-you-want-a-reply",
fieldset: {
legend: {
text: "Do you want a reply?"
}
},
items: [
{
id: "do-you-want-a-reply",
value: "yes",
text: "Yes",
checked: values["do-you-want-a-reply"] === "yes",
conditional: {
html: yesHTML
}
},
{
value: "no",
text: "No",
checked: values["do-you-want-a-reply"] === "no"
}
],
errorMessage: errors["do-you-want-a-reply"]
}) }}

{{ govukButton({
text: "Send message"
}) }}
</form>
</div>
</div>
{% endblock %}
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"cookie-parser": "^1.4.4",
"cssnano": "^4.1.7",
"express": "^4.16.4",
"express-validator": "^5.3.1",
"glob": "^7.1.3",
"gulp": "^3.9.1",
"gulp-better-rollup": "3.1.0",
Expand Down

0 comments on commit a2add05

Please sign in to comment.