diff --git a/app/data/session-data-defaults.js b/app/data/session-data-defaults.js index 95a505bc..fab42980 100644 --- a/app/data/session-data-defaults.js +++ b/app/data/session-data-defaults.js @@ -22,11 +22,17 @@ module.exports = { // Insert values here highestPageId: 0, + pages: [], + + highestGroupId: 0, + groups: [], + + pagesOrder: [], + action: '', publish: 'GOV.UK', authentication: 'email', payments: 'no', - pages: [], status: 'Draft', confirmationTitle: 'Your form has been submitted', checkAnswersTitle: 'Check your answers before submitting your form', diff --git a/app/routes.js b/app/routes.js index 5761a4da..5f8d42f6 100644 --- a/app/routes.js +++ b/app/routes.js @@ -7,17 +7,18 @@ const govukPrototypeKit = require('govuk-prototype-kit') const router = govukPrototypeKit.requests.setupRouter() // Add your routes here - - const path = require('path') const sessionDataDefaults = require('./data/session-data-defaults.js') const returningSessionDataDefaults = require('./data/returning-session-data-defaults') const returningSessionDataDefaultsA11y = require('./data/returning-session-data-defaults-a11y') +/* MARKDOWN +=========== */ + // Markdown support const markdown = require('@lfdebrux/nunjucks-markdown') -// Used to add govuk classes to additional guidance markdown for end user view (Runner) +// Used to add govuk classes to “additional guidance” markdown for end user view (Runner) const { marked } = require('marked'); const GovukHTMLRenderer = require('govuk-markdown') const renderer = new GovukHTMLRenderer() @@ -37,10 +38,12 @@ router.use(markdown.setupPlugin(marked.parse)) // Should be used after any operation that reorders pages. setPageIndexToArrayPosition = (page, index) => { page.pageIndex = index + page['index'] = index return page } -// ROUTES FOR EXAMPLE FORMS +/* ROUTES FOR EXAMPLE FORMS +=========================== */ // Run this code when a form is submitted to '/example-2/eligibility-check-answer' router.post('/example-2/eligibility-check-answer', function (req, res) { @@ -56,7 +59,6 @@ router.post('/example-2/eligibility-check-answer', function (req, res) { res.redirect('/example-2/question-1') } }) - // Run this code when a form is submitted to '/example-2/save-progress-check' router.post('/example-2/save-progress-check', function (req, res) { // Make a variable and give it the value from 'save-progress' @@ -286,7 +288,7 @@ Adding pages to a form router.get('/form-designer/clear-empty', function (req, res) { // remove empty pageData if there is only one object (pageIndex) in array const pages = req.session.data.pages.filter(element => { - if (Object.keys(element).length > 1) { + if (Object.keys(element).length > 2) { return true } return false @@ -297,48 +299,100 @@ router.get('/form-designer/clear-empty', function (req, res) { // reset highestPageId to number of pages req.session.data.highestPageId = parseInt(pages.length - 1) + // remove empty groupData if there is only one object (groupIndex) in array + const groups = req.session.data.groups.filter(element => { + if (Object.keys(element).length > 3) { + return true + } + return false + }) + // Save the groups + req.session.data.groups = groups + + // reset highestPageId to number of groups + req.session.data.highestGroupId = parseInt(groups.length - 1) + return res.redirect(`/form-designer/your-questions`) }) // Your form task list page - used to load and clear out success pageData +/* TODO: this breaks the re-ordering buttons by overwriting the pageOrder from scratch. Need to find a way to avoid this, but still make sure we add new questions on load */ +/* +1. Get current pagesOrder +2. Compare the objects in the array to see if page or group is missing +3. If new group or page add this to pagesOrder +4. Otherwise, if this is the first time generating the pagesOrder do the while loop +*/ +router.use('/form-designer/your-questions', function (req, res, next) { + var { groups, pages } = req.session.data + + // create new tempArray - to be combined group and page lists + const newPagesOrder = [] + // try a loop over the pages + let i = 0; + let index = 0; + while (i < pages.length) { + // if “addToGroup” is not null + if (pages[i].addToGroup != null) { + // set group to be the group found associated to the page + var group = groups.find(function(element) { return element.groupIndex == pages[i].addToGroup }) + // set temporary array of pages to associated with this group + var groupPages = [] + // using this group, check if the next questions are also in the same group + // this will start the loop where we are and should only go to the end of the pages added + while (i < pages.length && pages[i].addToGroup == group.groupIndex) { + // add page to group, if “addToGroup” is the same as the “groupIndex” + groupPages.push(pages[i]); + // increment loop count + i++; + } + // push group into “newPagesOrder” array with associated pages within it + newPagesOrder.push({ 'index': index, 'group': group, 'pages': groupPages }) + } else { + // push page into “newPagesOrder” array + newPagesOrder.push({ 'index': index, 'page': pages[i] }) + // increment loop count + i++; + } + index++; + } + + // set new “pagesOrder” array in session data so we can use it elsewhere + req.session.data.pagesOrder = newPagesOrder + + next(); +}) // could we also add timer to the notification banner here? // .govuk-notification-banner__header router.get('/form-designer/your-questions', function (req, res) { - - // remove empty pageData if there is only one object (pageIndex) in array - const pages = req.session.data.pages.filter(element => { - if (Object.keys(element).length > 1) { - return true - } - return false - }) - // Save the pages - req.session.data.pages = pages - - // reset highestPageId to number of pages - req.session.data.highestPageId = parseInt(pages.length - 1) - - var successMessage = req.session.data.successMessage + var { pagesOrder, successMessage } = req.session.data req.session.data.successMessage = undefined + return res.render('form-designer/your-questions', { + pagesOrder: pagesOrder, successMessage: successMessage }) }) - // Route for user marking questions as complete router.post('/form-designer/your-questions', function (req, res) { - const { isQuestionsComplete } = req.session.data + const { isQuestionsComplete, pages, action } = req.session.data + + // clear the action + req.session.data.action = undefined // content to display in notification banners var saved = 'Your questions have been saved' var savedAndComplete = 'Your questions have been saved and marked as complete' const errors = {} - // if no option is selected, then error - if (!isQuestionsComplete?.length) { - errors.isQuestionsComplete = { - text: 'Select yes if you have finished adding and editing your questions', - href: "#isQuestionsComplete" + // are there questions added to the form, if so check to see if we have answered the mark as complete question + if ((pages.length > 0) && (action == 'continue')) { + // if no option is selected, then error + if (!isQuestionsComplete?.length) { + errors.isQuestionsComplete = { + text: 'Select yes if you have finished adding and editing your questions', + href: "#isQuestionsComplete" + } } } @@ -350,14 +404,30 @@ router.post('/form-designer/your-questions', function (req, res) { if(containsErrors) { res.render('form-designer/your-questions', { errors, errorList, containsErrors }) } else { - if(isQuestionsComplete === 'yes') { - // set a success message for saving and marking as complete - req.session.data.successMessage = savedAndComplete - } else { - // set a success message for saving - req.session.data.successMessage = saved + // what action has been selected + if (action == 'addQuestion') { + if (req.session.data.addJourney == 'addAnother1') { + // add another answer journey - pre question version (Prototype 1 / Option 4 on Mural board) + res.redirect(`/form-designer/groups/group-or-question`) + } else { + // add a new question + res.redirect(`/form-designer/pages/new`) + } + } else if (action == 'addRoute') { + // add a new question route + res.redirect(`/form-designer/question-routes/new-condition`) + } else if (action =='continue') { + // save and continue + if(isQuestionsComplete === 'yes') { + // set a success message for saving and marking as complete + req.session.data.successMessage = savedAndComplete + } else { + // set a success message for saving + req.session.data.successMessage = saved + } + // back to “create your form” task list + res.redirect('/form-designer/your-form') } - res.redirect('/form-designer/your-form') } }) @@ -366,11 +436,32 @@ router.post('/form-designer/your-questions', function (req, res) { Managing questions in a form ===== */ +// Delete user selected question +getDeleteQuestion = function (req, res) { + const pageIndex = parseInt(req.params.pageId, 10) + const pageData = req.session.data.pages[pageIndex] + + const groupIndex = parseInt(req.params.groupIndex, 10) + const groupData = req.session.data.groups[groupIndex] + + if(!(pageIndex in req.session.data.pages)) { + throw Error('Page not found'); + } + + res.render('form-designer/pages/delete.html', { + pageData, + groupData + }) +} +router.get('/form-designer/pages/:pageId/delete', getDeleteQuestion) +router.get('/form-designer/groups/:groupId/pages/:pageId/delete', getDeleteQuestion) // Route used to delete question -router.post('/form-designer/pages/:pageId/delete', function (req, res) { +deleteQuestion = function (req, res) { const { action } = req.session.data - const pageIndex = parseInt(req.params.pageId, 10) const shouldDelete = req.session.data.delete + const pageIndex = parseInt(req.params.pageId, 10) + + // clear actions req.session.data.action = undefined req.session.data.delete = undefined @@ -408,43 +499,38 @@ router.post('/form-designer/pages/:pageId/delete', function (req, res) { req.session.data.pages = pages return res.redirect('/form-designer/clear-empty') } else if(action === 'delete' && shouldDelete === 'No') { - return res.redirect(`/form-designer/pages/${pageIndex}/edit`) + return res.redirect(`./check-question`) } else { return res.redirect(req.path) } -}) - -// Delete user selected question -router.get('/form-designer/pages/:pageId/delete', function (req, res) { - const pageIndex = parseInt(req.params.pageId, 10) - const pageData = req.session.data.pages[pageIndex] - - if(!(pageIndex in req.session.data.pages)) { - throw Error('Page not found'); - } +} +router.post('/form-designer/pages/:pageId/delete', deleteQuestion) +router.post('/form-designer/groups/:groupId/pages/:pageId/delete', deleteQuestion) - res.render('form-designer/pages/delete.html', { - pageData - }) -}) // Route used by the reordering buttons in your-questions.html -router.get('/form-designer/pages/:pageId/reorder/:direction', function (req, res) { +reorder = function (req, res) { const { pageId, direction } = req.params - const newArrayPosition = direction === 'down' ? pageId : pageId - 2 - const { pages } = req.session.data + const newArrayPosition = direction === 'down' ? parseInt(pageId) + 1 : parseInt(pageId) - 1 + const { pagesOrder } = req.session.data - const pageToMove = pages.splice(pageId - 1, 1)[0] - pages.splice(newArrayPosition, 0, pageToMove) + const pageToMove = pagesOrder.splice(pageId, 1)[0] + pagesOrder.splice(newArrayPosition, 0, pageToMove) // content to display in notification banners - var successMessage = '‘' + pageToMove['long-title'] + '’' + ' has moved ' + direction + ' to number ' + (parseInt(newArrayPosition) + 1) + var successMessage = '' + if (Object.hasOwn(pageToMove, 'group')) { + successMessage = '‘' + pageToMove.group.groupName + '’' + ' has moved ' + direction + ' to position ' + (parseInt(newArrayPosition) + 1) + } else { + successMessage = '‘' + pageToMove.page['long-title'] + '’' + ' has moved ' + direction + ' to number ' + (parseInt(newArrayPosition) + 1) + } - req.session.data.pages = pages.map(setPageIndexToArrayPosition) + req.session.data.pagesOrder = pagesOrder.map(setPageIndexToArrayPosition) req.session.data.successMessage = successMessage res.redirect('/form-designer/clear-empty') -}) +} +router.get('/form-designer/pages/:pageId/reorder/:direction', reorder) /* ===== @@ -634,7 +720,7 @@ router.get('/form-designer/pages/:pageId/preview', function (req, res) { }) }) -// This is just for convience to to the new-tab preview for this page +// This is just for convience to the new-tab preview for this page router.get('/form-designer/pages/:pageId/view', function (req, res) { return res.redirect(`/form-designer/view/${req.params.pageId}`) }) @@ -645,10 +731,16 @@ router.post('/form-designer/preview/:pageId(\\d+)', function (req, res) { req.session.data.cya = undefined var pageId = req.params.pageId var pageIndex = parseInt(pageId) + var pageData = req.session.data.pages[pageIndex] const isLastQuestionPage = pageIndex === (req.session.data.pages.length - 1) - // if last question in form OR user clicked on change link from CYA, then go to CYA - if(isLastQuestionPage || cya === 'true') { + var repeatQuestion = pageData.repeatQuestion ? pageData.repeatQuestion : null + + if(repeatQuestion === 'Yes') { + // if this is a single repeating question go to summary of answers listed + return res.redirect(`${pageIndex}` + '/page-repeat-summary') + } else if(isLastQuestionPage || cya === 'true') { + // if last question in form OR user clicked on change link from CYA, then go to CYA return res.redirect('check-answers') } else { return res.redirect(`${pageIndex + 1}`) @@ -662,6 +754,8 @@ router.get('/form-designer/preview/:pageId(\\d+)', function (req, res) { var pageData = req.session.data.pages[pageIndex] const isLastQuestionPage = pageIndex === (req.session.data.pages.length - 1) + var repeatQuestion = pageData.repeatQuestion ? pageData.repeatQuestion : null + if (pageData) { var markdownContent = pageData['additional-guidance-text'] } @@ -670,11 +764,60 @@ router.get('/form-designer/preview/:pageId(\\d+)', function (req, res) { pageId: pageId, pageIndex: pageIndex, pageData: pageData, + pageRepeats: repeatQuestion, + isLastQuestionPage, + markdownContent: markdownContent + }) +}) + +// Renders the new-tab page preview, set to a specific page +router.get('/form-designer/preview/:pageId(\\d+)/page-repeat-summary', function (req, res) { + var pageId = req.params.pageId + var pageIndex = parseInt(pageId) + var pageData = req.session.data.pages[pageIndex] + const isLastQuestionPage = pageIndex === (req.session.data.pages.length - 1) + + var repeatQuestion = pageData.repeatQuestion ? pageData.repeatQuestion : null + + console.log(repeatQuestion) + + if (pageData) { + var markdownContent = pageData['additional-guidance-text'] + } + + res.render('form-designer/preview/page-repeat-summary', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + pageRepeats: repeatQuestion, isLastQuestionPage, markdownContent: markdownContent }) }) +// Routing for new-tab page previews, set to a specific page +router.post('/form-designer/preview/:pageId(\\d+)/page-repeat-summary', function (req, res) { + var addAnother = req.session.data.addAnother + var cya = req.session.data.cya + req.session.data.cya = undefined + var pageId = req.params.pageId + var pageIndex = parseInt(pageId) + var pageData = req.session.data.pages[pageIndex] + const isLastQuestionPage = pageIndex === (req.session.data.pages.length - 1) + + var minLoop = pageData.minLoop ? pageData.minLoop : null + var maxLoop = pageData.maxLoop ? pageData.maxLoop : null + + if(addAnother === 'yes') { + return res.redirect(`../${pageIndex}`) + } else if(isLastQuestionPage || cya === 'true') { + // if last question in form OR user clicked on change link from CYA, then go to CYA + return res.redirect('../check-answers') + } else { + return res.redirect(`../${pageIndex + 1}`) + } +}) + /* ===== Routing for setting an email steps @@ -1022,6 +1165,9 @@ router.get('/prototype-admin/show-data', (req, res, next) => { /* Use the routes file in pages for adding and editing questions */ router.use('/pages', require('./views/form-designer/pages/\_routes')) +/* Use the routes file in groups for adding and editing groups */ +router.use('/groups', require('./views/form-designer/groups/\_routes')) + /* Use the routes file in product-pages for groups and members routes */ router.use('/product-pages', require('./views/product-pages/\_routes')) diff --git a/app/views/form-builder-prototypes.html b/app/views/form-builder-prototypes.html index aac8054d..8d45bc69 100644 --- a/app/views/form-builder-prototypes.html +++ b/app/views/form-builder-prototypes.html @@ -21,10 +21,6 @@

{{ pageTitle }}

Admin prototype

-

- View the admin prototype -

-

A form builder with the following features:

@@ -36,6 +32,27 @@

Admin prototype

  • questions are designed via a form, rather than directly edited
  • +

    + Form builder with multiple answers journeys +

    +

    + View prototype 1
    + Asking what the form creator wants to add +

    +

    + View prototype 2
    + Adding questions before adding functionality +

    + +
    + +

    + Basic form builder without complex features +

    +

    + View the admin prototype +

    +

    diff --git a/app/views/form-designer/groups/_routes.js b/app/views/form-designer/groups/_routes.js new file mode 100644 index 00000000..7545441c --- /dev/null +++ b/app/views/form-designer/groups/_routes.js @@ -0,0 +1,180 @@ +const govukPrototypeKit = require('govuk-prototype-kit') +const router = govukPrototypeKit.requests.setupRouter() + +/* CREATING A NEW GROUP +======================= */ + +// What do you want to add? - new question or question set (group) +router.post('/form-designer/groups/group-or-question', function (req, res) { + var groupQuestions = req.session.data.groupQuestions + + if (groupQuestions == 'newGroup') { + // add a new question set (group) + res.redirect(`/form-designer/groups/new`) + } else { + // add a new question + res.redirect(`/form-designer/pages/new`) + } +}) + +// Create a new question set (group) - button journeys +router.get('/form-designer/groups/new', function (req, res) { + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + // remove empty groupData if there is only one object (groupId) in array + const groups = req.session.data.groups.filter(element => { + if (Object.keys(element).length > 3) { + return true + } + return false + }) + // Save the groups + req.session.data.groups = groups + + // reset highestGroupId to number of groups + req.session.data.highestGroupId = parseInt(groups.length - 1) + + var nextGroupId = req.session.data.groups.length + + if (!groupData) { + req.session.data.groups.push({ + 'groupIndex': nextGroupId + }) + } + // add a new question set (group) + res.redirect(`/form-designer/groups/${nextGroupId}/edit-group`) +}) + +// Edit question set (group) - display +router.get('/form-designer/groups/:groupId(\\d+)/edit-group', function (req, res) { + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + var link = req.session.data.link + + return res.render('form-designer/groups/edit-group', { + link: link, + groupData: groupData + }) +}) +// Route used to find correct next step +router.post('/form-designer/groups/:groupId(\\d+)/edit-group', function (req, res) { + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + var action = req.session.data.action + + var errors = {}; + + var groupName = req.session.data.groupName + req.session.data.groupName = undefined + // if no name given, then throw an error + if (!groupName || !groupName.length) { + errors['groupName'] = { + text: 'Give your question set a name', + href: "#group-name" + } + } else { + groupData['groupName'] = groupName + } + + var minLoop = req.session.data.minLoop + req.session.data.minLoop = undefined + // if no minimum loops given, then throw an error + if (!minLoop || !minLoop.length) { + errors['minLoop'] = { + text: 'Give your question set a minimum number of repeats', + href: "#minimum-loop" + } + } else { + groupData['minLoop'] = minLoop + } + + var maxLoop = req.session.data.maxLoop + req.session.data.maxLoop = undefined + // if no maximum loops given, then throw an error + if (!maxLoop || !maxLoop.length) { + errors['maxLoop'] = { + text: 'Give your question set a maximum number of repeats', + href: "#maximum-loop" + } + } else { + groupData['maxLoop'] = maxLoop + } + + // Convert the errors into a list, so we can use it in the template + const errorList = Object.values(errors) + // If there are no errors, redirect the user to the next page + // otherwise, show the page again with the errors set + const containsErrors = errorList.length > 0 + // If there are errors on the page, redisplay it with the errors + if(containsErrors) { + return res.render('form-designer/groups/edit-group', { + groupData: groupData, + errors, + errorList, + containsErrors + }) + } else { + if (action == 'saveChanges') { + // add a new question + res.redirect(`/form-designer/groups/${groupId}/check-group`) + } else { + // add a new question + res.redirect(`/form-designer/groups/${groupId}/pages/new`) + } + } +}) + +// Check question set (group) - display +router.get('/form-designer/groups/:groupId(\\d+)/check-group', function (req, res) { + var { groups, pages } = req.session.data + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + // create new tempArray - to be combined group and page lists + const pagesOrder = [] + // try a loop over the pages + let i = 0; + while (i < pages.length) { + // if “addToGroup” is not null + if (pages[i].addToGroup != null) { + // set group to be the group found associated to the page + var group = groups.find(function(element) { return element.groupIndex == pages[i].addToGroup }) + // set temporary array of pages to associated with this group + var groupPages = [] + // using this group, check if the next questions are also in the same group + // this will start the loop where we are and should only go to the end of the pages added + while (i < pages.length && pages[i].addToGroup == group.groupIndex) { + // add page to group, if “addToGroup” is the same as the “groupIndex” + groupPages.push(pages[i]); + // increment loop count + i++; + } + // push group into “pagesOrder” array with associated pages within it + pagesOrder.push({ 'group': group, 'pages': groupPages }) + } else { + // push page into “pagesOrder” array + pagesOrder.push({ 'page': pages[i] }) + // increment loop count + i++; + } + } + + // set new “pagesOrder” array in session data so we can use it elsewhere + req.session.data.pagesOrder = pagesOrder + + return res.render('form-designer/groups/check-group', { + pagesOrder, + groupData, + groupId + }) +}) +// Route used to find next step +router.post('/form-designer/groups/:groupId(\\d+)/check-group', function (req, res) { + // return to your form page + res.redirect(`/form-designer/clear-empty`) +}) + +module.exports = router \ No newline at end of file diff --git a/app/views/form-designer/groups/add-questions.html b/app/views/form-designer/groups/add-questions.html new file mode 100644 index 00000000..702bb709 --- /dev/null +++ b/app/views/form-designer/groups/add-questions.html @@ -0,0 +1,63 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'Which questions do you want to add to this group?' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ data.groupName or '[groupName]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {{ data.groupName or '[groupName]' }} + {{ govukCheckboxes({ + name: "groupQuestions", + fieldset: { + legend: { + text: pageName, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + } + }, + hint: { + text: "Select all that apply." + }, + items: [ + { + value: "question1", + text: "1. Question text" + }, + { + value: "question2", + text: "2. Question text" + }, + { + value: "question3", + text: "3. Question text" + } + ] + }) }} + + {{ govukButton({ + text: "Save and continue" + }) }} +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/groups/check-group.html b/app/views/form-designer/groups/check-group.html new file mode 100644 index 00000000..0dc32232 --- /dev/null +++ b/app/views/form-designer/groups/check-group.html @@ -0,0 +1,124 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'Edit your question set' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ groupData.groupName or '[groupName]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {{ groupData.groupName or '[setName]' }} +

    {{ pageName }}

    + +

    About this question set

    + + {{ govukSummaryList({ + classes: "govuk-!-margin-bottom-9", + rows: [ + { + key: { + text: "Question set name" + }, + value: { + text: groupData.groupName or '[setName]' + }, + actions: { + items: [ + { + href: "edit-group?changelink=change#group-name", + text: "Change", + visuallyHiddenText: " question set name" + } + ] + } + }, + { + key: { + text: "Number of times this set can be answered" + }, + value: { + html: "Min: " + (groupData.minLoop or '0') + "
    Max: " + (groupData.maxLoop or '5') + }, + actions: { + items: [ + { + href: "edit-group?changelink=change#minimum-loop", + text: "Change", + visuallyHiddenText: " number of times this set can be answered" + } + ] + } + } + ] + }) }} + +

    Questions added to this set

    + +
    + {% for object in pagesOrder %} + {% if (object.group) and (object.group.groupIndex == groupId) -%} + {% for page in object.pages -%} + + {% set questionTitle = page["long-title"] or "Question " + (page["pageIndex"]|int + 1) %} + {% if page['questionOptional'] == 'questionOptional' %} + {% set questionTitle = questionTitle + ' (optional)' %} + {% endif %} + +
    +
    + {{ loop.index }} +
    +
    + {{ questionTitle }} +
    +
    +
    +
    + {{ govukButton({ + html: "Move up Question " + loop.index + ". " + questionTitle + "", + classes: "govuk-button--secondary", + href: "pages/" + (page.pageIndex | int + 1) + "/reorder/up" + }) }} + + {{ govukButton({ + html: "Move down Question " + loop.index + ". " + questionTitle + "", + classes: "govuk-button--secondary", + href: "pages/" + (page.pageIndex | int + 1) + "/reorder/down" + }) }} +
    +
    + + Edit Question {{loop.index}}. {{questionTitle}} + +
    +
    + {% endfor %} + {% endif %} + {% endfor %} +
    + + {{ govukButton({ + text: "Save and continue" + }) }} +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/groups/choose-group.html b/app/views/form-designer/groups/choose-group.html new file mode 100644 index 00000000..8d3f18ec --- /dev/null +++ b/app/views/form-designer/groups/choose-group.html @@ -0,0 +1,66 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'Choose which question set to add this question to' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {% set namePrefix = "pages[" + pageIndex + "]" %} + + Question {{ pageId | int + 1 }} +
    +
    + +

    + {{ pageName }} +

    +
    +
    + {% for group in data.groups %} +
    + + +
    + {% endfor %} +
    +
    +
    + +
    + {{ govukButton({ + text: "Create new question set", + classes: "govuk-button--secondary", + name: "action", + value: "addNewGroup" + }) }} +
    + + {{ govukButton({ + text: "Continue" + }) }} +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/groups/delete-group.html b/app/views/form-designer/groups/delete-group.html new file mode 100644 index 00000000..bf2781ac --- /dev/null +++ b/app/views/form-designer/groups/delete-group.html @@ -0,0 +1,56 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'Are you sure you want to delete this group?' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ data.groupName or '[groupName]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {{ data.groupName or '[groupName]' }} + {{ govukRadios({ + name: "deleteGroup", + fieldset: { + legend: { + text: pageName, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + } + }, + items: [ + { + value: "Yes", + text: "Yes" + }, + { + value: "No", + text: "No" + } + ] + }) }} + + {{ govukButton({ + text: "Save and continue" + }) }} +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/groups/edit-group.html b/app/views/form-designer/groups/edit-group.html new file mode 100644 index 00000000..d33c160c --- /dev/null +++ b/app/views/form-designer/groups/edit-group.html @@ -0,0 +1,114 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'Create a new question set' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {{ data.formTitle or '[formTitle]' }} +

    {{ pageName }}

    + +

    + A question set lets you ask someone for multiple pieces of information related to one thing. +

    +

    + This means you do not need to manually duplicate questions that may require more than one answer. +

    +

    + It also lets people decide how many times they need to answer such questions. +

    + + {{ govukInput({ + label: { + text: "Give this question set a name", + classes: "govuk-label--m" + }, + hint: { + text: "Use a descriptive name - for example, ‘Applicant information’" + }, + id: "group-name", + name: "groupName", + value: groupData['groupName'], + errorMessage: { text: errors['groupName'].text } if errors['groupName'].text + }) }} + + {% call govukFieldset({ + legend: { + text: "How many times can people answer this question set?", + classes: "govuk-fieldset__legend--m" + } + }) %} + + {{ govukInput({ + formGroup: { + classes: "govuk-!-display-inline-block govuk-!-margin-right-4" + }, + label: { + text: "Min" + }, + classes: "govuk-input--width-2", + id: "minimum-loop", + name: "minLoop", + value: groupData['minLoop'], + errorMessage: { text: errors['minLoop'].text } if errors['minLoop'].text + }) }} + + {{ govukInput({ + formGroup: { + classes: "govuk-!-display-inline-block" + }, + label: { + text: "Max" + }, + classes: "govuk-input--width-3", + id: "maximum-loop", + name: "maxLoop", + value: groupData['maxLoop'], + errorMessage: { text: errors['maxLoop'].text } if errors['maxLoop'].text + }) }} + + {% endcall %} + + {% if (data.addJourney == 'addAnother2') %} + {{ govukButton({ + text: "Save and continue", + name: "action", + value: "saveGroup" + }) }} + {% elif (data.changelink == 'change') %} + {{ govukButton({ + text: "Save and continue", + name: "action", + value: "saveChanges" + }) }} + {% else %} + {{ govukButton({ + text: "Save and add questions", + name: "action", + value: "saveAndAddQuestion" + }) }} + {% endif %} +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/groups/group-or-question.html b/app/views/form-designer/groups/group-or-question.html new file mode 100644 index 00000000..1d72925b --- /dev/null +++ b/app/views/form-designer/groups/group-or-question.html @@ -0,0 +1,66 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'What do you want to add?' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back to your questions + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {{ data.formTitle or '[formTitle]' }} + {{ govukRadios({ + name: "groupQuestions", + fieldset: { + legend: { + text: pageName, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + } + }, + items: [ + { + value: "newQuestion", + text: "Single question only" + }, + { + value: "newQuestionRepeats", + text: "Single question that can be answered multiple times" + }, + { + value: "newGroup", + text: "Set of questions that can be answered multiple times" + } + ] + }) }} + + {{ govukButton({ + text: "Continue" + }) }} + +

    + + Back to your questions + +

    +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/pages/_routes.js b/app/views/form-designer/pages/_routes.js index 85cd15bb..17f3cd41 100644 --- a/app/views/form-designer/pages/_routes.js +++ b/app/views/form-designer/pages/_routes.js @@ -5,17 +5,22 @@ const router = govukPrototypeKit.requests.setupRouter() ========================== */ // Create a new page or question route - button journeys -router.get('/form-designer/pages/new', function (req, res) { +newPage = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] - var action = req.session.data.action - req.session.data.action = undefined + var repeatQuestion = undefined + if ((req.session.data.groupQuestions) && (req.session.data.groupQuestions == 'newQuestionRepeats')) { + repeatQuestion = 'Yes' + } + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + + /* Can we change this to remove empty pageData if question isn’t marked as "questionSaved": "Yes" */ // remove empty pageData if there is only one object (pageIndex) in array const pages = req.session.data.pages.filter(element => { - if (Object.keys(element).length > 1) { + if (Object.hasOwn(element, 'questionSaved')) { return true } return false @@ -26,33 +31,40 @@ router.get('/form-designer/pages/new', function (req, res) { // reset highestPageId to number of pages req.session.data.highestPageId = parseInt(pages.length - 1) - if (action === 'addRoute') { - // add a new question route - res.redirect(`/form-designer/question-routes/new-condition`) - } else { + var nextPageId = req.session.data.pages.length - var nextPageId = req.session.data.pages.length - - if (!pageData) { - req.session.data.pages.push({ - 'pageIndex': nextPageId - }) - } + if (!pageData) { + req.session.data.pages.push({ + 'pageIndex': nextPageId, + 'addToGroup': groupId, + 'repeatQuestion': repeatQuestion + }) + } + + if (groupId != null) { + // add a new question to this group + res.redirect(`/form-designer/groups/${groupId}/pages/${nextPageId}/edit-answer-type`) + } else { // add a new question res.redirect(`/form-designer/pages/${nextPageId}/edit-answer-type`) } -}) +} +router.get('/form-designer/pages/new', newPage) +router.get('/form-designer/groups/:groupId(\\d+)/pages/new', newPage) /* ANSWER TYPE ============== */ -// Edit answer type - display -router.get('/form-designer/pages/:pageId(\\d+)/edit-answer-type', function (req, res) { +// Edit answer type - display +editAnswerTypeGet = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var groupData = req.session.data.groups[groupId] + // get the previous page URL var previousPage = req.session.data.referer // now we can set the back link data (text and url) @@ -62,16 +74,22 @@ router.get('/form-designer/pages/:pageId(\\d+)/edit-answer-type', function (req, pageId: pageId, pageIndex: pageIndex, pageData: pageData, + groupData: groupData, previousPageLink: tempArray[0].previousPageLink, previousPageText: tempArray[0].previousPageText }) -}) +} +router.get('/form-designer/pages/:pageId(\\d+)/edit-answer-type', editAnswerTypeGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-answer-type', editAnswerTypeGet) + // Route used to find correct next step - answer type > settings page || edit question page -router.post('/form-designer/pages/:pageId(\\d+)/edit-answer-type', function (req, res) { +editAnswerType = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var type = req.session.data.type req.session.data.type = undefined @@ -105,7 +123,8 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit-answer-type', function (req if (!pageData) { req.session.data.pages.push({ - 'pageIndex': nextPageId + 'pageIndex': nextPageId, + 'addToGroup': groupId }) } else { pageData['type'] = type @@ -129,16 +148,21 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit-answer-type', function (req return res.redirect('edit') } } -}) +} +router.post('/form-designer/pages/:pageId(\\d+)/edit-answer-type', editAnswerType) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-answer-type', editAnswerType) /* START selection from a list of options */ // Edit answer type settings - display -router.get('/form-designer/pages/:pageId(\\d+)/edit-select-question', function (req, res) { +editSelectQuestionGet = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var groupData = req.session.data.groups[groupId] + // get the previous page URL var previousPage = req.session.data.referer // now we can set the back link data (text and url) @@ -148,12 +172,16 @@ router.get('/form-designer/pages/:pageId(\\d+)/edit-select-question', function ( pageId: pageId, pageIndex: pageIndex, pageData: pageData, + groupData: groupData, previousPageText: tempArray[0].previousPageText, previousPageLink: tempArray[0].previousPageLink }) -}) +} +router.get('/form-designer/pages/:pageId(\\d+)/edit-select-question', editSelectQuestionGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-select-question', editSelectQuestionGet) + // Edit answer type settings - route to what is your question page for select from list answer type -router.post('/form-designer/pages/:pageId(\\d+)/edit-select-question', function (req, res) { +editSelectQuestion = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] @@ -197,17 +225,22 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit-select-question', function const nextPageId = req.session.data.pages.length res.redirect('edit-settings') } -}) +} +router.post('/form-designer/pages/:pageId(\\d+)/edit-select-question', editSelectQuestion) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-select-question', editSelectQuestion) /* END of selection from a list of options */ /* START secondary answer type settings */ // Edit answer type settings - display -router.get('/form-designer/pages/:pageId(\\d+)/edit-settings', function (req, res) { +editSettingsGet = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var groupData = req.session.data.groups[groupId] + // get the previous page URL var previousPage = req.session.data.referer // now we can set the back link data (text and url) @@ -225,12 +258,16 @@ router.get('/form-designer/pages/:pageId(\\d+)/edit-settings', function (req, re pageId: pageId, pageIndex: pageIndex, pageData: pageData, + groupData: groupData, previousPageText: tempArray[0].previousPageText, previousPageLink: tempArray[0].previousPageLink }) -}) +} +router.get('/form-designer/pages/:pageId(\\d+)/edit-settings', editSettingsGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-settings', editSettingsGet) + // Edit answer type settings - route used to find correct next step - settings page > edit question page -router.post('/form-designer/pages/:pageId(\\d+)/edit-settings', function (req, res) { +editSettings = function (req, res) { var action = req.session.data.action // clear the action so it doesn't change the next page load req.session.data.action = undefined @@ -373,7 +410,9 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit-settings', function (req, r return res.redirect('edit') } -}) +} +router.post('/form-designer/pages/:pageId(\\d+)/edit-settings', editSettings) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-settings', editSettings) /* END secondary answer type settings */ @@ -382,11 +421,14 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit-settings', function (req, r /* START editing question text and hint text */ // Edit a user-created question -router.get('/form-designer/pages/:pageId(\\d+)/edit', function (req, res) { +editQuestionGet = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var groupData = req.session.data.groups[groupId] + // get the previous page URL var previousPage = req.session.data.referer // now we can set the back link data (text and url) @@ -396,22 +438,34 @@ router.get('/form-designer/pages/:pageId(\\d+)/edit', function (req, res) { pageId: pageId, pageIndex: pageIndex, pageData: pageData, + groupData: groupData, previousPageText: tempArray[0].previousPageText, previousPageLink: tempArray[0].previousPageLink }) -}) -// Route used to find correct next step - edit question page > answer type -router.post('/form-designer/pages/:pageId(\\d+)/edit', function (req, res) { - var action = req.session.data.action - // clear the action so it doesn't change the next page load - req.session.data.action = undefined - - var additionalGuidance = req.session.data['additional-guidance'] +} +router.get('/form-designer/pages/:pageId(\\d+)/edit', editQuestionGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit', editQuestionGet) +// Route used to find correct next step - edit question page > answer type +editQuestion = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var additionalGuidance = req.session.data['additional-guidance'] + var { questionOptional } = req.session.data + + var repeatQuestion = req.session.data.repeatQuestion ? req.session.data.repeatQuestion : null + + var repeatQ = req.session.data.groupQuestions ? req.session.data.groupQuestions : null + if (repeatQ && repeatQ == 'newQuestionRepeats') { + pageData['repeatQuestion'] = 'Yes' + pageData['minLoop'] = req.session.data.minLoop ? req.session.data.minLoop : 1 + req.session.data.minLoop = undefined + pageData['maxLoop'] = req.session.data.maxLoop ? req.session.data.maxLoop : 99 + req.session.data.maxLoop = undefined + } + const errors = {}; if (!pageData['long-title']) { @@ -427,8 +481,8 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit', function (req, res) { } else { pageData['long-title'] = req.session.data['long-title'] } - req.session.data['long-title'] = undefined } + req.session.data['long-title'] = undefined // if hint text is added, add it to pageData if (req.session.data['hint-text']) { @@ -448,13 +502,43 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit', function (req, res) { } req.session.data['additional-guidance'] = undefined - // if question is made optional, add it to pageData - //reset if question is optional each time the form creator comes back to edit a question, to make sure if they unselect the checkbox it’ll update correctly - pageData['questionOptional'] = undefined - if (req.session.data['questionOptional']) { - pageData['questionOptional'] = req.session.data['questionOptional'] + /* IF we are on Add another journey / prototype 1 then we need to hide the optional question */ + /* + if (pageData['type'] != 'select') and ((data.groupQuestions != 'newQuestionRepeats') or (pageData.repeatQuestion != 'Yes') + don’t show optional question + else + show optional question + */ + + if ((pageData.type != 'select') && (req.session.data.addJourney) && ((!pageData.repeatQuestion) || (pageData.repeatQuestion != 'Yes'))) { + // if mandatory or optional hasn’t been selecgted, then throw an error + if (!questionOptional || !questionOptional.length) { + errors['questionOptional'] = { + text: 'Select ‘mandatory’ if people have to answer this question', + href: "#questionOptional" + } + } else { + pageData['questionOptional'] = questionOptional + } + req.session.data['questionOptional'] = undefined } - req.session.data['questionOptional'] = undefined + + + + + if ((req.session.data.addJourney) && (req.session.data.addJourney == 'addAnother2')) { + // if no additional guidance answer, then throw an error + if (!repeatQuestion || !repeatQuestion.length) { + errors['repeatQuestion'] = { + text: 'Select ‘Yes’ to let people answer this question more than once', + href: "#repeatQuestion" + } + // otherwise add question text to pageData + } else { + pageData['repeatQuestion'] = repeatQuestion + } + req.session.data['repeatQuestion'] = undefined +} // Convert the errors into a list, so we can use it in the template const errorList = Object.values(errors) @@ -472,21 +556,31 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit', function (req, res) { containsErrors }) } else if (additionalGuidance == 'Yes') { + // if user needs to add detailed guidance go here first return res.redirect(`additional-guidance`) + } else if (repeatQuestion == 'Yes') { + // else if user wants to repeat question go to check if it is part of a set or single question + return res.redirect(`add-to-set`) } else { + // if no detailed guidance, and no repeat then go to check question page return res.redirect(`check-question`) } -}) +} +router.post('/form-designer/pages/:pageId(\\d+)/edit', editQuestion) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit', editQuestion) /* END editing question text and hint text */ /* START adding additional guidance */ // Add additional guidance -router.get('/form-designer/pages/:pageId(\\d+)/additional-guidance', function (req, res) { +additionalGuidanceGet = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var groupData = req.session.data.groups[groupId] + var successMessage = req.session.data.successMessage req.session.data.successMessage = undefined @@ -499,13 +593,17 @@ router.get('/form-designer/pages/:pageId(\\d+)/additional-guidance', function (r pageId: pageId, pageIndex: pageIndex, pageData: pageData, + groupData: groupData, successMessage, previousPageText: tempArray[0].previousPageText, previousPageLink: tempArray[0].previousPageLink }) -}) +} +router.get('/form-designer/pages/:pageId(\\d+)/additional-guidance', additionalGuidanceGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/additional-guidance', additionalGuidanceGet) + // Add additional guidance text route -router.post('/form-designer/pages/:pageId(\\d+)/additional-guidance', function (req, res) { +additionalGuidance = function (req, res) { var action = req.session.data.action // clear the action so it doesn't change the next page load req.session.data.action = undefined @@ -513,6 +611,8 @@ router.post('/form-designer/pages/:pageId(\\d+)/additional-guidance', function ( var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + + var repeatQuestion = pageData.repeatQuestion ? pageData.repeatQuestion : null const errors = {}; const pageHeading = req.session.data['page-name'] @@ -563,18 +663,356 @@ router.post('/form-designer/pages/:pageId(\\d+)/additional-guidance', function ( } else if(action == 'previewGuidance') { req.session.data.successMessage = previewing res.redirect('additional-guidance#preview-guidance-text') + } else { + if ((req.session.data.addJourney == 'addAnother2') && (repeatQuestion == 'Yes')) { + // if user selected to repeat question go to check if it is part of a set or single question + return res.redirect(`add-to-set`) + } else { + // otherwise go to check question + res.redirect('check-question') + } + } +} +router.post('/form-designer/pages/:pageId(\\d+)/additional-guidance', additionalGuidance) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/additional-guidance', additionalGuidance) +/* END adding additional guidance */ + + +/* START add question to set */ +// GET add-to-set page +addToSetGet = function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + return res.render('form-designer/pages/add-to-set', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData + }) +} +router.get('/form-designer/pages/:pageId(\\d+)/add-to-set', addToSetGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/add-to-set', addToSetGet) +// POST add-to-set page +addToSetPost = function (req, res) { + var { addToSet } = req.session.data + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + var groupId = req.session.data.groups.length + + const errors = {}; + + // if no minimum loop has been provided, then throw an error + if (!addToSet || !addToSet.length) { + errors['addToSet'] = { + text: 'Select ‘Yes’ if you want to add this question to a set', + href: "#addToSet" + } + } else { + pageData['addToSet'] = req.session.data.addToSet + } + req.session.data.addToSet = undefined + + // Convert the errors into a list, so we can use it in the template + const errorList = Object.values(errors) + // If there are no errors, redirect the user to the next page + // otherwise, show the page again with the errors set + const containsErrors = errorList.length > 0 + // If there are errors on the page, redisplay it with the errors + if(containsErrors) { + return res.render('form-designer/pages/add-to-set', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + errors, + errorList, + containsErrors + }) + } else { + if (addToSet == 'Yes') { + if (req.session.data.groups.length > 0) { + // if there are existing question sets go to list page + res.redirect(`/form-designer/pages/${pageId}/choose-group`) + } else { + // otherwise go to add a new set + res.redirect(`/form-designer/pages/${pageId}/groups/${groupId}/new`) + } + } else { + res.redirect('add-loop') + } + } +} +router.post('/form-designer/pages/:pageId(\\d+)/add-to-set', addToSetPost) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/add-to-set', addToSetPost) + +// GET add-loop page +addLoopGet = function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + return res.render('form-designer/pages/add-loop', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData + }) +} +router.get('/form-designer/pages/:pageId(\\d+)/add-loop', addLoopGet) +// POST add-loop page +addLoop = function (req, res) { + var { minLoop, maxLoop } = req.session.data + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + const errors = {}; + + // if no minimum loop has been provided, then throw an error + if (!minLoop || !minLoop.length) { + errors['minLoop'] = { + text: 'Enter the minimum number of times this question needs to be answered', + href: "#minimum-loop" + } + } else { + pageData['minLoop'] = minLoop + } + req.session.data.minLoop = undefined + + // if no minimum loop has been provided, then throw an error + if (!maxLoop || !maxLoop.length) { + errors['maxLoop'] = { + text: 'Enter the maximum number of times this question can be answered', + href: "#maximum-loop" + } + } else { + pageData['maxLoop'] = maxLoop + } + req.session.data.maxLoop = undefined + + // Convert the errors into a list, so we can use it in the template + const errorList = Object.values(errors) + // If there are no errors, redirect the user to the next page + // otherwise, show the page again with the errors set + const containsErrors = errorList.length > 0 + // If there are errors on the page, redisplay it with the errors + if(containsErrors) { + return res.render('form-designer/pages/add-loop', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + errors, + errorList, + containsErrors + }) } else { res.redirect('check-question') } +} +router.post('/form-designer/pages/:pageId(\\d+)/add-loop', addLoop) + +// GET - render group/choose-group page +chooseGroup = function (req, res) { + var { groups, pages } = req.session.data + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + return res.render('form-designer/groups/choose-group', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + groups: groups, + groupData: groupData + }) +} +router.get('/form-designer/pages/:pageId(\\d+)/choose-group', chooseGroup) +// POST groups/choose-group page +editGroupPost = function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + var groupId = req.session.data.addToGroup + var groupData = req.session.data.groups[groupId] + + var action = req.session.data.action + + const errors = {}; + + // if no set name given, then throw an error + if ((action != 'addNewGroup') && (!groupId || !groupId.length)) { + errors['groupId'] = { + text: 'Select the question set to add this question to or create a new set', + href: "#addToGroup" + } + } else { + pageData['addToGroup'] = groupId + } + req.session.data.addToGroup = undefined + + // get the previous page URL + var previousPage = req.session.data.referer.split('/') + previousPage = previousPage[previousPage.length - 1] + + // Convert the errors into a list, so we can use it in the template + const errorList = Object.values(errors) + // If there are no errors, redirect the user to the next page + // otherwise, show the page again with the errors set + const containsErrors = errorList.length > 0 + // If there are errors on the page, redisplay it with the errors + if(containsErrors) { + return res.render('form-designer/groups/choose-group', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + groupData: groupData, + errors, + errorList, + containsErrors + }) + } else { + if (action === 'addNewGroup') { + res.redirect(`/form-designer/groups/new`) + } else { + res.redirect(`/form-designer/pages/${pageId}/check-question?referrer=` + previousPage ) + } + } +} +router.post('/form-designer/pages/:pageId(\\d+)/choose-group', editGroupPost) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/choose-group', editGroupPost) + + +// Create a new group +// Create a new question set (group) - button journeys +router.get('/form-designer/pages/:pageId(\\d+)/groups/:groupId(\\d+)/new', function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + // remove empty groupData if there is only one object (groupId) in array + const groups = req.session.data.groups.filter(element => { + if (Object.keys(element).length > 1) { + return true + } + return false + }) + // Save the groups + req.session.data.groups = groups + + // reset highestGroupId to number of groups + req.session.data.highestGroupId = parseInt(groups.length - 1) + + var nextGroupId = req.session.data.groups.length + + if (!groupData) { + req.session.data.groups.push({ + 'groupIndex': nextGroupId + }) + } + // add a new question set (group) + res.redirect(`/form-designer/pages/${pageId}/groups/${groupId}/edit-group`) }) -/* END adding additional guidance */ +// GET - render groups/edit-group page +editGroup = function (req, res) { + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + return res.render('form-designer/groups/edit-group', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + groupData: groupData + }) +} +router.get('/form-designer/pages/:pageId(\\d+)/groups/:groupId(\\d+)/edit-group', editGroup) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-group', editGroup) +// POST groups/edit-group page +editGroupPost = function (req, res) { + var { groupName, minLoop, maxLoop } = req.session.data + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + var groupId = parseInt(req.params.groupId, 10) + var groupData = req.session.data.groups[groupId] + + const errors = {}; + + // if no set name given, then throw an error + if (!groupName || !groupName.length) { + errors['groupName'] = { + text: 'Give your question set a name', + href: "#group-name" + } + } else { + pageData['addToGroup'] = groupId + groupData['groupName'] = groupName + } + req.session.data.groupName = undefined + + // if no minimum loop has been provided, then throw an error + if (!minLoop || !minLoop.length) { + errors['minLoop'] = { + text: 'Enter the minimum number of times this question needs to be answered', + href: "#minimum-loop" + } + } else { + groupData['minLoop'] = minLoop + } + req.session.data.minLoop = undefined + + // if no minimum loop has been provided, then throw an error + if (!maxLoop || !maxLoop.length) { + errors['maxLoop'] = { + text: 'Enter the maximum number of times this question can be answered', + href: "#maximum-loop" + } + } else { + groupData['maxLoop'] = maxLoop + } + req.session.data.maxLoop = undefined + + // Convert the errors into a list, so we can use it in the template + const errorList = Object.values(errors) + // If there are no errors, redirect the user to the next page + // otherwise, show the page again with the errors set + const containsErrors = errorList.length > 0 + // If there are errors on the page, redisplay it with the errors + if(containsErrors) { + return res.render('form-designer/groups/edit-group', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + groupData: groupData, + errors, + errorList, + containsErrors + }) + } else { + res.redirect(`/form-designer/pages/${pageId}/check-question`) + } +} +router.post('/form-designer/pages/:pageId(\\d+)/groups/:groupId(\\d+)/edit-group', editGroupPost) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/edit-group', editGroupPost) + +/* END add question to set */ /* REVIEW AND SAVE QUESTION =========================== */ // Check your question - middleware -router.use('/form-designer/pages/:pageId(\\d+)/check-question', function (req, res, next) { +checkQuestionUse = function (req, res, next) { // remove empty pageData if there is only one object (pageIndex) in array const pages = req.session.data.pages.filter(element => { @@ -590,18 +1028,32 @@ router.use('/form-designer/pages/:pageId(\\d+)/check-question', function (req, r req.session.data.highestPageId = parseInt(pages.length - 1) next(); -}) +} +router.use('/form-designer/pages/:pageId(\\d+)/check-question', checkQuestionUse) +router.use('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/check-question', checkQuestionUse) // Check your question - display the page -router.get('/form-designer/pages/:pageId(\\d+)/check-question', function (req, res) { +checkQuestionGet = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var groupData = req.session.data.groups[groupId] + var editNextPageId = pageId + 1 - var nextActionText = 'Add a new question' + var nextActionText = 'Add a question' var nextActionURL = `../new` + if ((req.session.data.addJourney == 'addAnother1') && (pageData.addToGroup == null)) { + // start from the what do you want to add - single question, repeating question or question set + nextActionURL = `/form-designer/groups/group-or-question` + } + + if ((req.session.data.addJourney == 'addAnother1') && (pageData.addToGroup != null)) { + var nextActionText = 'Add a question to this set' + } + if (pageId < req.session.data.pages.length - 1) { nextActionText = 'Edit next question' nextActionURL = `../` + editNextPageId + `/check-question` @@ -624,6 +1076,7 @@ router.get('/form-designer/pages/:pageId(\\d+)/check-question', function (req, r pageId: pageId, pageIndex: pageIndex, pageData: pageData, + groupData: groupData, successMessage, nextActionText, nextActionURL, @@ -631,10 +1084,12 @@ router.get('/form-designer/pages/:pageId(\\d+)/check-question', function (req, r previousPageText: tempArray[0].previousPageText, previousPageLink: tempArray[0].previousPageLink }) -}) +} +router.get('/form-designer/pages/:pageId(\\d+)/check-question', checkQuestionGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/check-question', checkQuestionGet) // Check your question - route used to find correct next step - edit question page > answer type -router.post('/form-designer/pages/:pageId(\\d+)/check-question', function (req, res) { +checkQuestion = function (req, res) { var action = req.session.data.action // clear the action so it doesn't change the next page load req.session.data.action = undefined @@ -643,6 +1098,8 @@ router.post('/form-designer/pages/:pageId(\\d+)/check-question', function (req, var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + if (pageData['questionSaved']) { var existingQuestion = true } @@ -666,23 +1123,30 @@ router.post('/form-designer/pages/:pageId(\\d+)/check-question', function (req, } } - if (action === 'savePreview') { + if (action === 'completeSet') { + return res.redirect(`/form-designer/groups/${groupId}/check-group`) + } else if (action === 'savePreview') { return res.redirect(`preview-question`) } else { return res.redirect(req.path) } -}) +} +router.post('/form-designer/pages/:pageId(\\d+)/check-question', checkQuestion) +router.post('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/check-question', checkQuestion) /* PREVIEW QUESTION =================== */ // Preview question - display -router.get('/form-designer/pages/:pageId(\\d+)/preview-question', function (req, res) { +previewQuestionGet = function (req, res) { var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var groupId = req.params.groupId ? parseInt(req.params.groupId, 10) : null + var groupData = req.session.data.groups[groupId] + var successMessage = req.session.data.successMessage req.session.data.successMessage = undefined @@ -704,13 +1168,16 @@ router.get('/form-designer/pages/:pageId(\\d+)/preview-question', function (req, pageId: pageId, pageIndex: pageIndex, pageData: pageData, + groupData: groupData, successMessage, nextActionText, nextActionURL, previousPageText: tempArray[0].previousPageText, previousPageLink: tempArray[0].previousPageLink }) -}) +} +router.get('/form-designer/pages/:pageId(\\d+)/preview-question', previewQuestionGet) +router.get('/form-designer/groups/:groupId(\\d+)/pages/:pageId(\\d+)/preview-question', previewQuestionGet) /* SUPPORTING FUNCTIONS diff --git a/app/views/form-designer/pages/add-loop.html b/app/views/form-designer/pages/add-loop.html new file mode 100644 index 00000000..942ac253 --- /dev/null +++ b/app/views/form-designer/pages/add-loop.html @@ -0,0 +1,73 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'How many times can people answer this question?' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + Question {{ pageId | int + 1 }} + {% call govukFieldset({ + legend: { + text: pageName, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + }, + errorMessage: { text: errors['minLoop'].text } if errors['minLoop'].text + }) %} + + {{ govukInput({ + formGroup: { + classes: "govuk-!-display-inline-block govuk-!-margin-right-4" + }, + label: { + text: "Min" + }, + classes: "govuk-input--width-2", + id: "minimum-loop", + name: "minLoop", + value: pageData['minLoop'] + }) }} + + {{ govukInput({ + formGroup: { + classes: "govuk-!-display-inline-block" + }, + label: { + text: "Max" + }, + classes: "govuk-input--width-3", + id: "maximum-loop", + name: "maxLoop", + value: pageData['maxLoop'] + }) }} + + {% endcall %} + + {{ govukButton({ + text: "Continue" + }) }} + +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/pages/add-to-set.html b/app/views/form-designer/pages/add-to-set.html new file mode 100644 index 00000000..09fec249 --- /dev/null +++ b/app/views/form-designer/pages/add-to-set.html @@ -0,0 +1,62 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'Do you want to add this question to a set of questions about the same thing?' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }} - {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {# Back links are handled in routes.js #} + + Back + +{% endblock %} + +{% block content %} +
    +
    +
    + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {% set namePrefix = "pages[" + pageIndex + "]" %} + + Question {{ pageId | int + 1 }} + {{ govukRadios({ + name: "addToSet", + fieldset: { + legend: { + text: pageName, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + } + }, + items: [ + { + value: "Yes", + text: "Yes", + checked: checked(namePrefix + "['addToSet']", "Yes") + }, + { + value: "No", + text: "No", + checked: checked(namePrefix + "['addToSet']", "No") + } + ], + errorMessage: { text: errors['addToSet'].text } if errors['addToSet'].text + }) }} + + {{ govukButton({ + text: "Continue" + }) }} + +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/pages/additional-guidance.html b/app/views/form-designer/pages/additional-guidance.html index 093169d4..f08e6a03 100644 --- a/app/views/form-designer/pages/additional-guidance.html +++ b/app/views/form-designer/pages/additional-guidance.html @@ -6,13 +6,6 @@ {{ "Error: " if containsErrors }}{{pageTitle}} - GOV.UK Forms {% endblock %} -{% block beforeContent %} - {# Back links are handled in routes.js #} - - {{ previousPageText }} - -{% endblock %} - {% block content %}
    @@ -40,7 +33,9 @@

    }) }} {% endif %} - Question {{ pageId | int + 1 }} + + Question {{ pageId | int + 1 }} {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} - Part of {{ groupData.groupName or '[setName]' }}{%- endif %} +

    {{pageTitle}}

    @@ -174,15 +169,12 @@

    name: "action", value: "editPage" }) }} - - {# If we are not sure what the back link is going to don’t show the bottom link #} - {% if previousPageText !== 'Back' %} +

    - - {{ previousPageText }} + + Back to your questions

    - {% endif %}

    diff --git a/app/views/form-designer/pages/check-question.html b/app/views/form-designer/pages/check-question.html index aaa04d68..6a79a2ad 100644 --- a/app/views/form-designer/pages/check-question.html +++ b/app/views/form-designer/pages/check-question.html @@ -53,19 +53,6 @@ {{ pageTitle }} - GOV.UK Forms {% endblock %} -{# Overwrite back link if last action was to save #} -{% if successMessage %} -{% set previousPageText = 'Back to your questions' %} -{% set previousPageLink = '/form-designer/clear-empty' %} -{% endif %} - -{% block beforeContent %} - {# Back links are handled in routes.js #} - - {{ previousPageText }} - -{% endblock %} - {% block content %}
    @@ -84,7 +71,7 @@

    • - + {{ nextActionText }}
    • @@ -103,8 +90,10 @@

      }) }} {% endif %} - Question {{ pageId | int + 1 }} -

      {{pageTitle}}

      + + Question {{ pageId | int + 1 }} {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} - Part of {{ groupData.groupName or '[setName]' }}{%- endif %} + +

      {{ pageTitle }}

      Answer settings

      @@ -241,19 +230,67 @@

      Your question

    + {% if (pageData['type'] != 'select') and ((data.groupQuestions != 'newQuestionRepeats') or (pageData.repeatQuestion != 'Yes')) %}
    - Make this question optional + Make this mandatory or optional
    - {{ 'Yes' if (pageData['questionOptional'] and 'questionOptional' in pageData['questionOptional']) else 'No' }} + {{ 'Optional' if ((pageData['questionOptional']) and ('questionOptional' in pageData['questionOptional'])) else 'Mandatory' }}
    - Change if question optional + Change Make this question optional + +
    +
    + {% endif %} + {% if data.addJourney == 'addAnother2' %} +
    +
    + Can be answered multiple times +
    +
    + {{ pageData['repeatQuestion'] }} +
    +
    + + Change Can be answered multiple times + +
    +
    + {% if pageData['repeatQuestion'] == 'Yes' %} +
    +
    + Add to a set of questions +
    +
    + {{ pageData['addToSet'] }} +
    +
    + + Change Add to a set of questions + +
    +
    + {% endif %} + {% endif %} + {% if (pageData['repeatQuestion'] == 'Yes') and (pageData['addToGroup'] == null) %} +
    +
    + Number of times question can be answered +
    +
    + Min: {{ pageData['minLoop'] }}
    + Max: {{ pageData['maxLoop'] }} +
    +
    + + Change number of times question can be answered
    + {% endif %} {% if pageData['additional-guidance'] == 'Yes' %} @@ -289,6 +326,51 @@

    Guidance

    {% endif %} + {% if (pageData['addToSet'] == 'Yes') or (pageData['addToGroup'] != null) -%} + {% for group in data.groups -%} + {% if group.groupIndex == pageData.addToGroup -%} +

    Part of a question set

    +
    +
    +
    + Question set name +
    +
    + {{ group.groupName }} +
    +
    + {% if (data.addJourney == 'addAnother2') and (data.referrer != 'choose-group') %} + + Change question set name + + {% else %} + + Change question set + + {% endif %} +
    +
    +
    +
    + Number of times this set can be answered +
    +
    + Min: {{ group['minLoop'] }}
    + Max: {{ group['maxLoop'] }} +
    +
    + {% if (data.addJourney == 'addAnother2') and (data.referrer != 'choose-group') %} + + Change number of times this set can be answered + + {% endif %} +
    +
    +
    + {%- endif %} + {%- endfor %} + {%- endif %} +
    @@ -305,6 +387,17 @@

    Guidance

    name: "action", value: "savePreview" }) }} + + {% if editingExistingQuestion === 'Yes' -%} + {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} + {{ govukButton({ + classes: "govuk-button--secondary", + text: "Finish question set", + name: "action", + value: "completeSet" + }) }} + {%- endif %} + {%- endif %}
    {% if editingExistingQuestion === 'Yes' %} @@ -322,14 +415,11 @@

    Guidance

    {% endif %} - {# If we are not sure what the back link is going to don’t show the bottom link #} - {% if previousPageText !== 'Back' %}

    - - {{ previousPageText }} + + Back to your questions

    - {% endif %}
    diff --git a/app/views/form-designer/pages/delete.html b/app/views/form-designer/pages/delete.html index a3679768..7ed618e6 100644 --- a/app/views/form-designer/pages/delete.html +++ b/app/views/form-designer/pages/delete.html @@ -6,10 +6,6 @@ {{ "Error: " if containsErrors }}{{pageTitle}} - GOV.UK Forms {% endblock %} -{% block beforeContent %} - Back -{% endblock %} - {% block content %}
    diff --git a/app/views/form-designer/pages/edit-answer-type.html b/app/views/form-designer/pages/edit-answer-type.html index de8065bf..a14ea536 100644 --- a/app/views/form-designer/pages/edit-answer-type.html +++ b/app/views/form-designer/pages/edit-answer-type.html @@ -6,13 +6,6 @@ {{ "Error: " if containsErrors }}{{ pageTitle }} - GOV.UK Forms {% endblock %} -{% block beforeContent %} - {# Back links are handled in routes.js #} - - {{ previousPageText }} - -{% endblock %} - {% block content %}
    @@ -25,7 +18,9 @@ }) }} {% endif %} - Question {{ pageId | int + 1 }} + + Question {{ pageId | int + 1 }} {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} - Part of {{ groupData.groupName or '[setName]' }}{%- endif %} + {% set namePrefix = "pages[" + pageIndex + "]" %} @@ -110,14 +105,11 @@ value: "editPage" }) }} - {# If we are not sure what the back link is going to don’t show the bottom link #} - {% if previousPageText !== 'Back' %}

    - - {{ previousPageText }} + + Back to your questions

    - {% endif %}
    diff --git a/app/views/form-designer/pages/edit-select-question.html b/app/views/form-designer/pages/edit-select-question.html index 062b6789..ab60dad4 100644 --- a/app/views/form-designer/pages/edit-select-question.html +++ b/app/views/form-designer/pages/edit-select-question.html @@ -19,13 +19,6 @@ {{ "Error: " if containsErrors }}{{ pageTitle }} - GOV.UK Forms {% endblock %} -{% block beforeContent %} - {# Back links are handled in routes.js #} - - {{ previousPageText }} - -{% endblock %} - {% block content %}
    @@ -38,7 +31,9 @@ }) }} {% endif %} - Question {{ pageId | int + 1 }} + + Question {{ pageId | int + 1 }} {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} - Part of {{ groupData.groupName or '[setName]' }}{%- endif %} + {% set namePrefix = "pages[" + pageIndex + "]" %} @@ -62,14 +57,11 @@ text: "Continue" }) }} - {# If we are not sure what the back link is going to don’t show the bottom link #} - {% if previousPageText !== 'Back' %}

    - - {{ previousPageText }} + + Back to your questions

    - {% endif %}
    diff --git a/app/views/form-designer/pages/edit-settings.html b/app/views/form-designer/pages/edit-settings.html index 029f1882..0bb30ddc 100644 --- a/app/views/form-designer/pages/edit-settings.html +++ b/app/views/form-designer/pages/edit-settings.html @@ -18,13 +18,6 @@ {{ "Error: " if containsErrors }}{{ pageTitle }} - GOV.UK Forms {% endblock %} -{% block beforeContent %} - {# Back links are handled in routes.js #} - - {{ previousPageText }} - -{% endblock %} - {% block content %}
    @@ -37,7 +30,9 @@ }) }} {% endif %} - Question {{ pageId | int + 1 }} + + Question {{ pageId | int + 1 }} {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} - Part of {{ groupData.groupName or '[setName]' }}{%- endif %} + {% if pageData['type'] === 'personName' %}

    {{ pageTitle }}

    {% endif %} @@ -288,15 +283,11 @@

    {{pageTitle}}

    value: "editPage" }) }} - {# If we are not sure what the back link is going to don’t show the bottom link #} - {% if previousPageText !== 'Back' %}

    - - {{ previousPageText }} + + Back to your questions

    - {% endif %} -
    diff --git a/app/views/form-designer/pages/edit.html b/app/views/form-designer/pages/edit.html index 8fdde3e7..9536893e 100644 --- a/app/views/form-designer/pages/edit.html +++ b/app/views/form-designer/pages/edit.html @@ -57,13 +57,6 @@ {{ "Error: " if containsErrors }}{{ pageTitle }} - GOV.UK Forms {% endblock %} -{% block beforeContent %} - {# Back links are handled in routes.js #} - - {{ previousPageText }} - -{% endblock %} - {% block content %}
    @@ -77,7 +70,9 @@ }) }} {% endif %} - Question {{ pageId | int + 1 }} + + Question {{ pageId | int + 1 }} {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} - Part of {{ groupData.groupName or '[setName]' }}{%- endif %} +

    {{pageTitle}}

    {% set namePrefix = "pages[" + pageIndex + "]" %} @@ -144,31 +139,99 @@

    {{pageTitle}}

    }) }} - {% if pageData['type'] != 'select' %} + {% if (pageData['type'] != 'select') and ((data.groupQuestions != 'newQuestionRepeats') or (pageData.repeatQuestion != 'Yes')) %}
    - {{ govukCheckboxes({ + {{ govukRadios({ idPrefix: "questionOptional", name: "questionOptional", fieldset: { legend: { - text: "Make this question optional", + text: "Should this question be mandatory or optional?", classes: "govuk-fieldset__legend--m" } }, - hint: { - text: "All questions are mandatory unless you make them optional." - }, items: [ + { + value: "mandatory", + text: "Mandatory", + checked: checked(namePrefix + "['questionOptional']", "mandatory") + }, { value: "questionOptional", - text: "Make this question optional", + text: "Optional", hint: { - text: "‘(optional)’ will be added to the end of the question text" + text: "We’ll add ‘(optional)’ to the end of the question text." }, checked: checked(namePrefix + "['questionOptional']", "questionOptional") } - ] + ], + errorMessage: { text: errors['questionOptional'].text } if errors['questionOptional'].text + }) }} + {% endif %} + + {% if data.addJourney == 'addAnother1' %} + {% if data.groupQuestions == 'newQuestionRepeats' %} + {% call govukFieldset({ + legend: { + text: "How many times can people answer this question?", + classes: "govuk-fieldset__legend--m" + } + }) %} + + {{ govukInput({ + formGroup: { + classes: "govuk-!-display-inline-block govuk-!-margin-right-4" + }, + label: { + text: "Min" + }, + classes: "govuk-input--width-2", + id: "minimum-loop", + name: "minLoop", + value: pageData['minLoop'], + errorMessage: { text: errors['minLoop'].text } if errors['minLoop'].text + }) }} + + {{ govukInput({ + formGroup: { + classes: "govuk-!-display-inline-block" + }, + label: { + text: "Max" + }, + classes: "govuk-input--width-3", + id: "maximum-loop", + name: "maxLoop", + value: pageData['maxLoop'], + errorMessage: { text: errors['maxLoop'].text } if errors['maxLoop'].text + }) }} + + {% endcall %} + {% endif %} + {% elif data.addJourney == 'addAnother2' %} + {{ govukRadios({ + classes: "govuk-radios--inline", + name: "repeatQuestion", + fieldset: { + legend: { + text: "Can people answer this question more than once?", + classes: "govuk-fieldset__legend--m" + } + }, + items: [ + { + value: "Yes", + text: "Yes", + checked: checked(namePrefix + "['repeatQuestion']", "Yes") + }, + { + value: "No", + text: "No", + checked: checked(namePrefix + "['repeatQuestion']", "No") + } + ], + errorMessage: { text: errors['repeatQuestion'].text } if errors['repeatQuestion'].text }) }} {% endif %} @@ -178,14 +241,11 @@

    {{pageTitle}}

    value: "editPage" }) }} - {# If we are not sure what the back link is going to don’t show the bottom link #} - {% if previousPageText !== 'Back' %}

    - - {{ previousPageText }} + + Back to your questions

    - {% endif %}
    diff --git a/app/views/form-designer/pages/preview-question.html b/app/views/form-designer/pages/preview-question.html index 508ae6c2..5a5ec6e3 100644 --- a/app/views/form-designer/pages/preview-question.html +++ b/app/views/form-designer/pages/preview-question.html @@ -86,7 +86,9 @@ }) }} {% endif %} - Question {{ pageId | int + 1 }} + + Question {{ pageId | int + 1 }} {% if (data.addJourney == 'addAnother1') and (pageData['addToGroup'] != null) -%} - Part of {{ groupData.groupName or '[setName]' }}{%- endif %} +

    {{pageTitle}}

    diff --git a/app/views/form-designer/pages/preview.html b/app/views/form-designer/pages/preview.html index 48fa17c5..1d3bb72b 100644 --- a/app/views/form-designer/pages/preview.html +++ b/app/views/form-designer/pages/preview.html @@ -21,7 +21,7 @@ {% endif %} {% set pageTitle = pageData['long-title'] or 'Question text' %} -{% if pageData['questionOptional'] %} +{% if pageData['questionOptional'] == 'questionOptional' %} {% set pageTitle = pageTitle + ' (optional)' %} {% endif %} diff --git a/app/views/form-designer/partials/your-questions-live-form.html b/app/views/form-designer/partials/your-questions-live-form.html index 35496f94..3973fef8 100644 --- a/app/views/form-designer/partials/your-questions-live-form.html +++ b/app/views/form-designer/partials/your-questions-live-form.html @@ -1,7 +1,7 @@ {% for page in data.pages %}

    -

    {{ page['long-title'] }}{{ ' (optional)' if page.questionOptional }}

    +

    {{ page['long-title'] }}{{ ' (optional)' if page.questionOptional == 'questionOptional' }}

    diff --git a/app/views/form-designer/preview/check-answers.html b/app/views/form-designer/preview/check-answers.html index 892c37c0..53059d9f 100644 --- a/app/views/form-designer/preview/check-answers.html +++ b/app/views/form-designer/preview/check-answers.html @@ -21,7 +21,7 @@

    {% for page in data.pages -%} {% set questionTitle = page["long-title"] or "Page " + page["pageIndex"] %} - {% if page['questionOptional'] %} + {% if page['questionOptional'] == 'questionOptional' %} {% set questionTitle = questionTitle + ' (optional)' %} {% endif %} @@ -63,11 +63,11 @@

    Not completed {% endif %} -
    - - Change {{questionTitle}} - -
    +
    + + Change {{questionTitle}} + +

    {% endif %} diff --git a/app/views/form-designer/preview/page-repeat-summary.html b/app/views/form-designer/preview/page-repeat-summary.html new file mode 100644 index 00000000..acaa369a --- /dev/null +++ b/app/views/form-designer/preview/page-repeat-summary.html @@ -0,0 +1,167 @@ +{% extends "layout-govuk-form-preview.html" %} +{% set mainClasses = "main--draft govuk-main-wrapper--auto-spacing" %} + +{% set pageName = 'You have added ' + pageId | length | plural("answer") %} + +{% set timesAnswer = 0 %} +{% set answer -%} +{% for page in data.pages -%} + {% if page.pageIndex == pageId %} + {% if (data[loop.index0]) or (data[loop.index0 + '-year']) or (data[loop.index0 + '-address-street-address']) or (data[loop.index0 + '-address-line-1']) or (data[loop.index0 + '-address-postcode']) or (data[loop.index0 + '-full-name']) or (data[loop.index0 + '-first-name']) %} + {% if page['type'] == 'personName' %} + {% if (page['title'] === 'yes') and (data[loop.index0 + '-name-title']) %}{{data[loop.index0 + '-name-title']}}{% endif %} + {% if page['input'] === 'single-field' %} + {{data[loop.index0 + '-full-name']}} + {% else %} + {{data[loop.index0 + '-first-name']}} + {% if data[loop.index0 + '-middle-names'] %}{{data[loop.index0 + '-middle-names']}}{% endif %} + {{data[loop.index0 + '-last-name']}} + {% endif %} + {% elif page['type'] == 'date' -%} + {% if (data[loop.index0 + '-day']) %}{{data[loop.index0 + '-day']}}/{% endif %}{% if (data[loop.index0 + '-month']) %}{{data[loop.index0 + '-month']}}{% if (data[loop.index0 + '-year']) %}/{% endif %}{% endif %}{% if (data[loop.index0 + '-year']) %}{{data[loop.index0 + '-year']}}{% endif %} + {%- elif page['type'] == 'address' %} + {% if ('uk-address' in page['input']) and not ('international-address' in page['input']) %} + {{data[loop.index0 + '-address-line-1']}}
    + {% if data[loop.index0 + '-address-line-2'] %}{{data[loop.index0 + '-address-line-2']}}
    {% endif %} + {{data[loop.index0 + '-address-town']}}
    + {{data[loop.index0 + '-address-postcode']}} + {% else %} + {{data[loop.index0 + '-address-street-address'] | replace(",","") | replace(".","") | nl2br | safe}}
    + {% if data[loop.index0 + '-address-country-name'] %}{{data[loop.index0 + '-address-country-name']}}{% endif %} + {% endif %} + {% elif page['type'] == 'select' and not page['listSettings'].includes('oneOption') %} + {{data[loop.index0]|join(", ") if data[loop.index0]}} + {% else %} + {{data[loop.index0]}} + {% endif %} + {% else %} + Not completed + {% endif %} + + {% set timesAnswer = loop.index %} + {% endif%} +{%- endfor %} +{%- endset %} + +{% block beforeContent %} + {% set prevPageId = pageId | int - 1 %} + {% if data.cya %} + Back + {% elif prevPageId >= 0 %} + Back + {% endif %} +{% endblock %} + +{% block pageTitle %} + {{ pageName }} - Preview - {{ data.formTitle or '[formTitle]' }} - GOV.UK +{% endblock %} + +{% block content %} + {% set nextPageId = pageId | int + 1 %} + {% set isLastQuestionPage = pageId == data['highestPageId'] %} + {% set formAction = "../check-answers-page-preview-new-tab" if isLastQuestionPage else nextPageId %} + +
    +
    +
    +

    {{ pageName }}

    + + {% if pageData.minLoop >= 2 %} +

    + You need to give at least {{ minLoop }} answers. +

    + {% endif %} + +
    + {% for page in data.pages -%} + {% if page.pageIndex == pageId %} +
    +
    + {{ loop.index }} +
    +
    + {{ answer }} +
    +
    + + Change {{ loop.index }}. {{ answer }} + +
    +
    + {% endif %} + {% endfor %} +
    + +

    + You have added {{ timesAnswer | plural("answer") }} of a maximum {{ pageData.maxLoop }}. +

    + + {% if timesAnswer == pageData.maxLoop %} + {{ govukInsetText({ + text: "You cannot add anymore as you have entered the maximum of " + pageData.maxLoop + '.' + }) }} + {% else %} + {{ govukRadios({ + classes: "govuk-radios--inline", + name: "addAnother", + fieldset: { + legend: { + text: "Do you need to add another answer?", + classes: "govuk-fieldset__legend--m" + } + }, + items: [ + { + value: "yes", + text: "Yes" + }, + { + value: "no", + text: "No" + } + ] + }) }} + {% endif %} + + {{ govukButton({ + text: "Continue", + attributes: { + target: "_parent" + } + }) }} + + {% if data['supportDetails'] %} + {% set supportTextHtml %} +
    + {% if 'email' in data['supportDetails'] -%} +

    Email

    +

    + {{data['emailSupport'] or 'support@department.gov.uk' | safe}} +

    + {%- endif %} + {% if 'phone' in data['supportDetails'] -%} +

    Phone

    +

    {{data['phoneSupport'] | striptags(true) | escape | nl2br }}

    +

    + Find out about call charges +

    + {%- endif %} + {% if 'online' in data['supportDetails'] -%} +

    Online

    +

    + {{data['onlineSupportText'] | safe}} (opens in new tab) +

    + {%- endif %} +
    + {% endset -%} + + {{ govukDetails({ + summaryText: "Get help with this form", + html: supportTextHtml + }) }} + {% endif %} + +
    +
    +
    +{% endblock %} diff --git a/app/views/form-designer/preview/page.html b/app/views/form-designer/preview/page.html index f5f32f9d..56b24e19 100644 --- a/app/views/form-designer/preview/page.html +++ b/app/views/form-designer/preview/page.html @@ -6,11 +6,10 @@ {% endif %} {% set pageTitle = pageData['long-title'] or 'Question text' %} -{% if pageData['questionOptional'] %} +{% if pageData['questionOptional'] == 'questionOptional' %} {% set pageTitle = pageTitle + ' (optional)' %} {% endif %} - {% block beforeContent %} {% set prevPageId = pageId | int - 1 %} {% if data.cya %} diff --git a/app/views/form-designer/question-routes/new-condition.html b/app/views/form-designer/question-routes/new-condition.html index b5ac3ef8..07eaa51a 100644 --- a/app/views/form-designer/question-routes/new-condition.html +++ b/app/views/form-designer/question-routes/new-condition.html @@ -50,7 +50,7 @@

    What you need to create a route

    - Go to your questions + Back to your questions

    diff --git a/app/views/form-designer/your-questions-BACKUP.html b/app/views/form-designer/your-questions-BACKUP.html new file mode 100644 index 00000000..f3d1c40a --- /dev/null +++ b/app/views/form-designer/your-questions-BACKUP.html @@ -0,0 +1,217 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageName = 'Add and edit your questions' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageName }}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + + Back to {{ "your form" if data['status'] === 'Live' else "create a form" }} + +{% endblock %} + +{% block content %} +
    +
    + + {% if data.successMessage %} + {{ govukNotificationBanner({ + type: 'success', + text: data.successMessage + }) }} + {% endif %} + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {{ data.formTitle or '[formTitle]' }} +

    {{ pageName }}

    +
    +
    Status
    +
    + {{ govukTag({ + text: data['status'], + classes: "govuk-tag--yellow" if data.status === 'Draft' else "govuk-tag--turquoise" + }) }} +
    +
    + + {% if data.status === 'Live' %} + {% include "./partials/your-questions-live-form.html" %} + {% else %} + +
    +
    + {{ govukButton({ + text: "Add a question", + classes: "govuk-button govuk-!-margin-bottom-3 govuk-!-margin-top-3", + name: "action", + value: "addQuestion" + }) }} + {{ govukButton({ + text: "Add a question route", + classes: "govuk-button govuk-button--secondary govuk-!-margin-bottom-3 govuk-!-margin-top-3", + name: "action", + value: "addRoute" + }) }} + {% if data.pages.length %} + + Preview this form + + {% endif %} +
    + + {% if data.pages.length %} + +

    + Your questions +

    +
    + {% set pageLoopCount = 0 %} + {% set groupLoopCount = 0 %} + {% for object in pagesOrder -%} + + {% if object.group -%} + + + {% set groupLoopCount = groupLoopCount + 1 %} + + {# if this is a question set show #} +
    +
    + Question set {{ object.group.groupIndex | int + 1 }} +
    +
    + {{ object.group.groupName }}
    + {% for page in object.pages -%} + {% set questionTitle = page["long-title"] or "Question " + ( loop.index ) %} + {% if page['questionOptional'] == 'questionOptional' %} + {% set questionTitle = questionTitle + ' (optional)' %} + {% endif %} + {{ loop.index }}. {{ questionTitle }}{% if not loop.last %}
    {% endif %} + {%- endfor %} +
    +
    +
    +
    + {{ govukButton({ + html: "Move up Group " + loop.index + ". " + object.group.groupName + "", + classes: "govuk-button--secondary", + href: "pages/" + ( loop.index ) + "/reorder/up" + }) }} + {{ govukButton({ + html: "Move down Group " + loop.index + ". " + object.group.groupName + "", + classes: "govuk-button--secondary", + href: "pages/" + ( loop.index ) + "/reorder/down" + }) }} +
    +
    + + Edit question set {{ loop.index }} + +
    +
    + + {% else %} + + + {% set pageLoopCount = pageLoopCount + 1 %} + + {% set questionTitle = object.page["long-title"] or "Question " + (object.page["pageIndex"]|int + 1) %} + {% if object.page['questionOptional'] == 'questionOptional' %} + {% set questionTitle = questionTitle + ' (optional)' %} + {% endif %} + +
    +
    + {{ pageLoopCount }} +
    +
    + {{ questionTitle }} +
    +
    +
    + {% if data.pages.length > 1 %} +
    + {% if object.page.pageIndex > 0 %} + {{ govukButton({ + html: "Move up Question " + loop.index + ". " + questionTitle + "", + classes: "govuk-button--secondary", + href: "pages/" + ( loop.index ) + "/reorder/up" + }) }} + {% endif %} + + {% if object.page.pageIndex < data.pages | length - 1 %} + {{ govukButton({ + html: "Move down Question " + loop.index + ". " + questionTitle + "", + classes: "govuk-button--secondary", + href: "pages/" + ( loop.index ) + "/reorder/down" + }) }} + {% endif %} +
    + {% endif %} +
    + + Edit Question {{loop.index}}. {{questionTitle}} + +
    +
    + {% endif %} + + {%- endfor %} +
    + + {% if data.status === 'Draft' %} + {{ govukRadios({ + classes: "govuk-radios", + idPrefix: "isQuestionsComplete", + name: "isQuestionsComplete", + fieldset: { + legend: { + text: "Have you finished editing your questions?", + isPageHeading: false, + classes: "govuk-fieldset__legend--m" + } + }, + hint: { + text: "Selecting ‘Yes’ will mark this task as complete. You’ll still be able to make changes if you need to." + }, + items: [ + { + value: "yes", + text: "Yes" + }, + { + value: "no", + text: "No, I’ll come back later" + } + ], + errorMessage: { text: errors['isQuestionsComplete'].text } if errors['isQuestionsComplete'].text + }) }} + {{ govukButton({ + text: "Save and continue", + name: "action", + value: "continue" + }) }} + {% endif %} + + {% endif %} + +
    + {% endif %} +
    +
    +{% endblock %} + +{% block pageScripts %} + +{% endblock %} diff --git a/app/views/form-designer/your-questions.html b/app/views/form-designer/your-questions.html index 4792bfe4..8f050e18 100644 --- a/app/views/form-designer/your-questions.html +++ b/app/views/form-designer/your-questions.html @@ -1,9 +1,9 @@ {% extends "layout-govuk-forms.html" %} -{% set pageTitle = 'Add and edit your questions' %} +{% set pageName = 'Add and edit your questions' %} {% block pageTitle %} - {{ "Error: " if containsErrors }}{{ pageTitle }}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms + {{ "Error: " if containsErrors }}{{ pageName }}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms {% endblock %} {% block beforeContent %} @@ -31,152 +31,179 @@ {% endif %} {{ data.formTitle or '[formTitle]' }} -

    {{ pageTitle }}

    +

    {{ pageName }}

    Status
    -
    - {{ govukTag({ - text: data['status'], - classes: "govuk-tag--yellow" if data.status === 'Draft' else "govuk-tag--turquoise" - }) }} -
    +
    + {{ govukTag({ + text: data['status'], + classes: "govuk-tag--yellow" if data.status === 'Draft' else "govuk-tag--turquoise" + }) }} +
    {% if data.status === 'Live' %} {% include "./partials/your-questions-live-form.html" %} {% else %} + +
    +
    + {{ govukButton({ + text: "Add a question", + classes: "govuk-button govuk-!-margin-bottom-3 govuk-!-margin-top-3", + name: "action", + value: "addQuestion" + }) }} + {{ govukButton({ + text: "Add a question route", + classes: "govuk-button govuk-button--secondary govuk-!-margin-bottom-3 govuk-!-margin-top-3", + name: "action", + value: "addRoute" + }) }} + {% if data.pages.length %} + + Preview this form + + {% endif %} +
    - -
    - {{ govukButton({ - text: "Add a question", - classes: "govuk-button govuk-!-margin-bottom-3 govuk-!-margin-top-3", - name: "action", - value: "addQuestion" - }) }} - {{ govukButton({ - text: "Add a question route", - classes: "govuk-button govuk-button--secondary govuk-!-margin-bottom-3 govuk-!-margin-top-3", - name: "action", - value: "addRoute" - }) }} - {% if data.pages.length %} - - Preview this form - - {% endif %} -
    -
    - - {% if data.pages.length %} - -

    - Your questions -

    -
    - - {% for page in data.pages -%} + {% if (pagesOrder.length or data.pagesOrder.length) and data.pages.length > 0 %} + +

    + Your questions +

    +
    + {% for object in pagesOrder -%} + + {% if object.group -%} +
    +
    + Question set {{ object.group.groupIndex | int + 1 }} +
    +
    + {{ object.group.groupName }}
    + {% for page in object.pages -%} + {% set questionTitle = page["long-title"] or "Question " + ( loop.index ) %} + {% if page['questionOptional'] == 'questionOptional' %} + {% set questionTitle = questionTitle + ' (optional)' %} + {% endif %} + {{ loop.index }}. {{ questionTitle }}{% if not loop.last %}
    {% endif %} + {%- endfor %} +
    +
    + {% if data.pagesOrder.length > 1 %} +
    +
    + {% if object.index > 0 %} + {{ govukButton({ + html: "Move up Group " + object.index + ". " + object.group.groupName + "", + classes: "govuk-button--secondary", + href: "pages/" + ( object.index ) + "/reorder/up" + }) }} + {% endif %} + + {% if object.index < data.pagesOrder | length - 1 %} + {{ govukButton({ + html: "Move down Group " + object.index + ". " + object.group.groupName + "", + classes: "govuk-button--secondary", + href: "pages/" + ( object.index ) + "/reorder/down" + }) }} + {% endif %} +
    +
    + {% endif %} + + Edit question set {{ object.index }} + +
    +
    + + {% else %} + + {% set questionTitle = object.page["long-title"] or "Question " + ( object.index | int + 1 ) %} + {% if object.page['questionOptional'] == 'questionOptional' -%} + {% set questionTitle = questionTitle + ' (optional)' %} + {%- endif %} + +
    +
    + {{ object.index | int + 1 }} +
    +
    + {{ questionTitle }} +
    +
    + {% if data.pagesOrder.length > 1 %} +
    +
    + {% if object.index > 0 %} + {{ govukButton({ + html: "Move up Question " + object.index + ". " + questionTitle + "", + classes: "govuk-button--secondary", + href: "pages/" + ( object.index ) + "/reorder/up" + }) }} + {% endif %} + + {% if object.index < data.pagesOrder | length - 1 %} + {{ govukButton({ + html: "Move down Question " + object.index + ". " + questionTitle + "", + classes: "govuk-button--secondary", + href: "pages/" + ( object.index ) + "/reorder/down" + }) }} + {% endif %} +
    +
    + {% endif %} + + Edit Question {{ object.index }}. {{questionTitle}} + +
    +
    + {% endif %} - {% set questionTitle = page["long-title"] or "Question " + (page["pageIndex"]|int + 1) %} - {% if page['questionOptional'] %} - {% set questionTitle = questionTitle + ' (optional)' %} - {% endif %} + {%- endfor %} +
    + + {% if data.status === 'Draft' %} + {{ govukRadios({ + classes: "govuk-radios", + idPrefix: "isQuestionsComplete", + name: "isQuestionsComplete", + fieldset: { + legend: { + text: "Have you finished editing your questions?", + isPageHeading: false, + classes: "govuk-fieldset__legend--m" + } + }, + hint: { + text: "Selecting ‘Yes’ will mark this task as complete. You’ll still be able to make changes if you need to." + }, + items: [ + { + value: "yes", + text: "Yes" + }, + { + value: "no", + text: "No, I’ll come back later" + } + ], + errorMessage: { text: errors['isQuestionsComplete'].text } if errors['isQuestionsComplete'].text + }) }} + {{ govukButton({ + text: "Save and continue", + name: "action", + value: "continue" + }) }} + {% endif %} - {% if questionTitle %} - -
    -
    - {{loop.index}} -
    -
    - - {{questionTitle}} - {#{% if page['page-name'] %}
    Guidance added{% endif %}#} - {#{% if page['page-name'] %}
    Page heading: {{page['page-name']}}{% endif %}#} -
    -
    -
    - {% if data.pages.length > 1 %} -
    - {% if page.pageIndex > 0 %} - {{ govukButton({ - html: "Move up Question " + loop.index + ". " + questionTitle + "", - classes: "govuk-button--secondary", - href: "pages/" + (page.pageIndex | int + 1) + "/reorder/up" - }) }} - {% endif %} - - {% if page.pageIndex < data.pages | length - 1 %} - {{ govukButton({ - html: "Move down Question " + loop.index + ". " + questionTitle + "", - classes: "govuk-button--secondary", - href: "pages/" + (page.pageIndex | int + 1) + "/reorder/down" - }) }} - {% endif %} -
    - {% endif %} -
    - - Edit Question {{loop.index}}. {{questionTitle}} - -
    -
    {% endif %} - {%- endfor %} -
    - - {% if data.status === 'Draft' %} -
    - {{ govukRadios({ - classes: "govuk-radios", - idPrefix: "isQuestionsComplete", - name: "isQuestionsComplete", - fieldset: { - legend: { - text: "Have you finished editing your questions?", - isPageHeading: false, - classes: "govuk-fieldset__legend--m" - } - }, - hint: { - text: "Selecting ‘Yes’ will mark this task as complete. You’ll still be able to make changes if you need to." - }, - items: [ - { - value: "yes", - text: "Yes" - }, - { - value: "no", - text: "No, I’ll come back later" - } - ], - errorMessage: { text: errors['isQuestionsComplete'].text } if errors['isQuestionsComplete'].text - }) }} - {{ govukButton({ - text: "Save and continue", - name: "action", - value: "continue" - }) }}
    - {% else %} -
    - {{ govukButton({ - text: "Save and continue", - name: "action", - value: "continue" - }) }} -
    - {% endif %} - - {% endif %} - {% endif %}
    -
    - {% endblock %} {% block pageScripts %} diff --git a/app/views/layout-govuk-forms.html b/app/views/layout-govuk-forms.html index f32d9fd6..a0bff089 100644 --- a/app/views/layout-govuk-forms.html +++ b/app/views/layout-govuk-forms.html @@ -19,6 +19,13 @@ }) }} {% endblock %} +{% block beforeContent %} + {# TO-DO: Back links sould be handled in routes.js #} + + Back + +{% endblock %} + {% if (GOVUKPrototypeKit.isDevelopment) %} {% set formsFooterItems = [ { diff --git a/package-lock.json b/package-lock.json index 85e31812..9991a359 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "@govuk-prototype-kit/common-templates": "1.2.2", "@govuk-prototype-kit/step-by-step": "^2.1.0", "@lfdebrux/nunjucks-markdown": "github:lfdebrux/govuk-prototype-kit-nunjucks-markdown-plugin#v0.0.3", + "@x-govuk/govuk-prototype-filters": "^1.4.0", "govuk-frontend": "^5.2.0", "govuk-markdown": "^0.4.0", "govuk-prototype-kit": "^13.4.0", @@ -114,6 +115,59 @@ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==" }, + "node_modules/@x-govuk/govuk-prototype-filters": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@x-govuk/govuk-prototype-filters/-/govuk-prototype-filters-1.4.0.tgz", + "integrity": "sha512-kFMypSr6jYlet5K1qKfLKrSASCPZlxhEYU7jv64zQc+48F+0a+fwgrKn1/FD/ocX1euzAoTOihYVnZYCFeDhAQ==", + "dependencies": { + "govuk-markdown": "^0.7.0", + "lodash": "^4.17.21", + "luxon": "^3.2.1", + "marked": "^12.0.0", + "marked-smartypants": "^1.0.0", + "pluralize": "^8.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "govuk-prototype-kit": "^13.0.0" + } + }, + "node_modules/@x-govuk/govuk-prototype-filters/node_modules/govuk-markdown": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/govuk-markdown/-/govuk-markdown-0.7.0.tgz", + "integrity": "sha512-eTy+0l9n+NQcYvXWlySgHSiFkiLFnfefZxKk8nBIy8njd+rJgTtSAun4UmDT+uUh2rHwrYLCq9pEQvsxzrk9+g==", + "dependencies": { + "highlight.js": "^11.5.0", + "marked": "^11.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@x-govuk/govuk-prototype-filters/node_modules/govuk-markdown/node_modules/marked": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", + "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@x-govuk/govuk-prototype-filters/node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/a-sync-waterfall": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", @@ -2057,6 +2111,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", @@ -2068,6 +2130,17 @@ "node": ">= 12" } }, + "node_modules/marked-smartypants": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/marked-smartypants/-/marked-smartypants-1.1.6.tgz", + "integrity": "sha512-38rdxcV3+EHrvoHioSrgBDvOmFb+TNcszZggrl15qe4MEfQxBArfSgsGgFP0YqHlGy8Rgoyi4gN4ThBWzwNJeA==", + "dependencies": { + "smartypants": "^0.2.2" + }, + "peerDependencies": { + "marked": ">=4 <13" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2492,6 +2565,14 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "engines": { + "node": ">=4" + } + }, "node_modules/portscanner": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", @@ -3032,6 +3113,15 @@ "node": ">=8" } }, + "node_modules/smartypants": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/smartypants/-/smartypants-0.2.2.tgz", + "integrity": "sha512-TzobUYoEft/xBtb2voRPryAUIvYguG0V7Tt3de79I1WfXgCwelqVsGuZSnu3GFGRZhXR90AeEYIM+icuB/S06Q==", + "bin": { + "smartypants": "bin/smartypants.js", + "smartypantsu": "bin/smartypantsu.js" + } + }, "node_modules/socket.io": { "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", @@ -3730,6 +3820,42 @@ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==" }, + "@x-govuk/govuk-prototype-filters": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@x-govuk/govuk-prototype-filters/-/govuk-prototype-filters-1.4.0.tgz", + "integrity": "sha512-kFMypSr6jYlet5K1qKfLKrSASCPZlxhEYU7jv64zQc+48F+0a+fwgrKn1/FD/ocX1euzAoTOihYVnZYCFeDhAQ==", + "requires": { + "govuk-markdown": "^0.7.0", + "lodash": "^4.17.21", + "luxon": "^3.2.1", + "marked": "^12.0.0", + "marked-smartypants": "^1.0.0", + "pluralize": "^8.0.0" + }, + "dependencies": { + "govuk-markdown": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/govuk-markdown/-/govuk-markdown-0.7.0.tgz", + "integrity": "sha512-eTy+0l9n+NQcYvXWlySgHSiFkiLFnfefZxKk8nBIy8njd+rJgTtSAun4UmDT+uUh2rHwrYLCq9pEQvsxzrk9+g==", + "requires": { + "highlight.js": "^11.5.0", + "marked": "^11.0.0" + }, + "dependencies": { + "marked": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", + "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==" + } + } + }, + "marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==" + } + } + }, "a-sync-waterfall": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", @@ -5204,11 +5330,24 @@ "yallist": "^4.0.0" } }, + "luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" + }, "marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==" }, + "marked-smartypants": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/marked-smartypants/-/marked-smartypants-1.1.6.tgz", + "integrity": "sha512-38rdxcV3+EHrvoHioSrgBDvOmFb+TNcszZggrl15qe4MEfQxBArfSgsGgFP0YqHlGy8Rgoyi4gN4ThBWzwNJeA==", + "requires": { + "smartypants": "^0.2.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -5499,6 +5638,11 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" + }, "portscanner": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", @@ -5890,6 +6034,11 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, + "smartypants": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/smartypants/-/smartypants-0.2.2.tgz", + "integrity": "sha512-TzobUYoEft/xBtb2voRPryAUIvYguG0V7Tt3de79I1WfXgCwelqVsGuZSnu3GFGRZhXR90AeEYIM+icuB/S06Q==" + }, "socket.io": { "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", diff --git a/package.json b/package.json index 294c34e9..d71eb680 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@govuk-prototype-kit/common-templates": "1.2.2", "@govuk-prototype-kit/step-by-step": "^2.1.0", "@lfdebrux/nunjucks-markdown": "github:lfdebrux/govuk-prototype-kit-nunjucks-markdown-plugin#v0.0.3", + "@x-govuk/govuk-prototype-filters": "^1.4.0", "govuk-frontend": "^5.2.0", "govuk-markdown": "^0.4.0", "govuk-prototype-kit": "^13.4.0",