diff --git a/src/assets/js/application.js b/src/assets/js/application.js index a207f019..547bf2a8 100644 --- a/src/assets/js/application.js +++ b/src/assets/js/application.js @@ -3,8 +3,14 @@ as it will be loaded into the base nunjucks template. */ +import CookieBanner from './components/cookie-banner.js' import initiateJsHiddenChecks from './js-hidden.js' +const initCookieBanner = () => { + return new CookieBanner(window.document) +} + window.addEventListener('load', () => { initiateJsHiddenChecks() + initCookieBanner() }) diff --git a/src/assets/js/components/cookie-banner.js b/src/assets/js/components/cookie-banner.js new file mode 100644 index 00000000..3cb14171 --- /dev/null +++ b/src/assets/js/components/cookie-banner.js @@ -0,0 +1,95 @@ +const cookieDefaults = { + cookieNames: { + preferenceCookie: 'cookies_preferences_set', + policyCookie: 'cookies_policy' + }, + cookieExpiryDays: 365, + cookiePath: '/', + defaultPolicyValue: { essential: true, settings: true, usage: true, campaigns: true } +} + +export default class CookieBanner { + constructor (document) { + this.document = document + this.banner = this.document.querySelector('.js-app-c-cookie-banner') + if (!this.banner) { + console.warn('Cookie banner element not found') + return + } + + this.form = this.banner.querySelector('.js-app-c-cookie-banner__form') + this.confirmationMessage = this.banner.querySelector('.js-app-c-cookie-banner__confirmation') + this.confirmationDecision = this.banner.querySelector('.js-app-c-cookie-banner__confirmation-decision') + this.acceptButton = this.banner.querySelector('.js-app-c-cookie-banner__accept') + this.rejectButton = this.banner.querySelector('.js-app-c-cookie-banner__reject') + this.hideButton = this.banner.querySelector('.js-app-c-cookie-banner__hide') + + this.init() + } + + init () { + if (this.getCookie(cookieDefaults.cookieNames.preferenceCookie) !== null) { + this.hideCookieBanner() + } + + this.acceptButton.addEventListener('click', this.accept.bind(this)) + this.rejectButton.addEventListener('click', this.reject.bind(this)) + this.hideButton.addEventListener('click', this.hideCookieBanner.bind(this)) + } + + accept () { + this.userCookiePolicyDecision(true) + } + + reject () { + this.userCookiePolicyDecision(false) + } + + userCookiePolicyDecision (userAcceptedCookiePolicy = true) { + this.setCookie( + cookieDefaults.cookieNames.preferenceCookie, + userAcceptedCookiePolicy, + cookieDefaults.cookieExpiryDays) + + this.setCookie( + cookieDefaults.cookieNames.policyCookie, + userAcceptedCookiePolicy ? cookieDefaults.defaultPolicyValue : null, + userAcceptedCookiePolicy ? cookieDefaults.cookieExpiryDays : 0 + ) + + this.showConfirmationMessage(userAcceptedCookiePolicy) + } + + setCookie (name, value, days) { + const expires = new Date() + expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000)) + this.document.cookie = `${name}=${JSON.stringify(value)};expires=${expires.toUTCString()};path=${cookieDefaults.cookiePath}` + } + + getCookie (name) { + const cookie = this.document.cookie + .split('; ') + .find(row => row.startsWith(name)) + + return cookie ? JSON.parse(cookie.split('=')[1]) : null + } + + showConfirmationMessage (userAcceptedCookiePolicy = true) { + this.form.classList.add('app-c-cookie-banner__form--hidden') + this.form.setAttribute('aria-hidden', 'true') + this.acceptButton.removeEventListener('click', this.accept.bind(this)) + this.rejectButton.removeEventListener('click', this.reject.bind(this)) + + if (!userAcceptedCookiePolicy) this.confirmationDecision.textContent = 'rejected' + this.confirmationMessage.classList.remove('app-c-cookie-banner__confirmation--hidden') + this.confirmationMessage.setAttribute('aria-hidden', 'false') + this.confirmationMessage.setAttribute('role', 'status') // Announce status to screen readers + } + + hideCookieBanner () { + if (this.banner) { + this.banner.style.display = 'none' + this.banner.setAttribute('aria-hidden', 'true') + } + } +} diff --git a/src/assets/scss/components/_cookie-banner.scss b/src/assets/scss/components/_cookie-banner.scss new file mode 100644 index 00000000..5294d8a2 --- /dev/null +++ b/src/assets/scss/components/_cookie-banner.scss @@ -0,0 +1,7 @@ +.app-c-cookie-banner__form--hidden { + display: none; +} + +.app-c-cookie-banner__confirmation--hidden { + display: none; +} diff --git a/src/assets/scss/index.scss b/src/assets/scss/index.scss index 6f63f5f6..c2c42f90 100644 --- a/src/assets/scss/index.scss +++ b/src/assets/scss/index.scss @@ -5,7 +5,7 @@ $govuk-global-styles: true; @import "src/assets/scss/_scrollable-container.scss"; @import "./step-by-step-nav.scss"; @import "./components/dataset-navigation"; - +@import "./components/cookie-banner"; .app-inset-text---error { border-left: 5px solid govuk-colour('red'); diff --git a/src/routes/cookies.js b/src/routes/cookies.js index 21139986..7ea00e3b 100644 --- a/src/routes/cookies.js +++ b/src/routes/cookies.js @@ -4,8 +4,23 @@ import nunjucks from 'nunjucks' const router = express.Router() router.get('/', (req, res) => { - const cookiesPage = nunjucks.render('cookies.html', {}) + const cookiesPage = nunjucks.render('cookies.html', { + cookiePreferences: req.cookies.cookies_preferences_set, + showCookieUpdatedMessage: req.cookies.cookies_preferences_set_updated + }) res.send(cookiesPage) }) +router.post('/update-preference', (req, res) => { + const defaultCookieExpiry = 1000 * 60 * 60 * 24 * 365 // 1 year + + res.cookie('cookies_preferences_set', req.body.accept_cookies, { maxAge: defaultCookieExpiry }) + res.cookie('cookies_preferences_set_updated', true, { maxAge: 1000 }) + res.cookie('cookies_policy', JSON.stringify({ essential: true, settings: true, usage: true, campaigns: true }), { + maxAge: req.body.accept_cookies === 'true' ? defaultCookieExpiry : 0 + }) + + res.redirect('/cookies') +}) + export default router diff --git a/src/views/components/cookie-banner.html b/src/views/components/cookie-banner.html new file mode 100644 index 00000000..f6275503 --- /dev/null +++ b/src/views/components/cookie-banner.html @@ -0,0 +1,64 @@ +{% from "govuk/components/cookie-banner/macro.njk" import govukCookieBanner %} + +{% if serviceType %} + {% set serviceName = serviceType | getFullServiceName %} +{% endif %} +{% set cookiePagePath = '/cookies' %} +{% set cookieHeader = "Cookies on " + serviceName %} + +{% set html %} +

We use some essential cookies to make this service work.

+

We’d also like to use analytics cookies so we can understand how you use the service and make improvements.

+{% endset %} + +{% set acceptHtml %} +

You’ve accepted additional cookies. You can change your cookie settings at any time.

+{% endset %} + + diff --git a/src/views/cookies.html b/src/views/cookies.html index b626585d..100f9ded 100644 --- a/src/views/cookies.html +++ b/src/views/cookies.html @@ -1,6 +1,10 @@ +{% from "govuk/components/radios/macro.njk" import govukRadios %} +{% from "govuk/components/button/macro.njk" import govukButton %} +{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %} + {% extends "layouts/main.html" %} -{% set pageName = 'Accessibility statement for Submit and update planning and housing data for England' %} +{% set pageName = 'Cookie notice for Submit and update planning and housing data for England' %} {% set markdownContent %} @@ -54,7 +58,6 @@ - ### Smartlook cookies (optional) We use Smartlook to measure how you use the Check planning and housing data for England service. This helps us to improve the service experience and make sure it’s meeting your needs. No personal data will be stored in the cookies. @@ -67,7 +70,7 @@ * how long you spend on each part * what you click on the service -The cookies do not store any information you add to the service. +The cookies do not store any information you add to the service. @@ -114,6 +117,54 @@ {% block content %} + {% if showCookieUpdatedMessage %} + {% set html %} +

+ You’ve updated your cookie preferences +

+

You can change your settings at any time by visiting this page.

+ {% endset %} + + {{ govukNotificationBanner({ + type: "success", + html: html + }) }} + {% endif %} + {{markdownContent | govukMarkdown(headingsStartWith="xl") | safe}} +
+
+

Change your cookie settings

+
+ {{ govukRadios({ + name: "accept_cookies", + idPrefix: "cookies-analytics", + fieldset: { + legend: { + text: "Do you want to accept analytics cookies?", + classes: "govuk-fieldset__legend--s" + } + }, + items: [ + { + value: "true", + text: "Yes", + checked: cookiePreferences == "true" + }, + { + value: "false", + text: "No", + checked: cookiePreferences == "false" + } + ] + }) }} + + {{ govukButton({ + text: "Save cookie settings" + }) }} + +
+
+ {% endblock content %} diff --git a/src/views/layouts/main.html b/src/views/layouts/main.html index e6a89a31..2ca18fe6 100644 --- a/src/views/layouts/main.html +++ b/src/views/layouts/main.html @@ -38,6 +38,8 @@ {% endblock %} {% block header %} + {% include "components/cookie-banner.html" %} + {{ govukHeader({ homepageUrl: homepageUrl, serviceName: serviceName, @@ -98,7 +100,7 @@

Get help

{% block bodyEnd %} {{ super()}} - {%block scripts %} + {% block scripts %}