diff --git a/app/data/returning-session-data-defaults-a11y.js b/app/data/returning-session-data-defaults-a11y.js index 1928e1a9..9936d713 100644 --- a/app/data/returning-session-data-defaults-a11y.js +++ b/app/data/returning-session-data-defaults-a11y.js @@ -1,73 +1,132 @@ /* -Provide default values for user session data. These are automatically added -via the `autoStoreData` middleware. Values will only be added to the -session if a value doesn't already exist. This may be useful for testing -journeys where users are returning or logging in to an existing application. - -============================================================================ - -Example usage: - -"full-name": "Sarah Philips", - -"options-chosen": [ "foo", "bar" ] - -============================================================================ +This is the latest version of return data for a dummy form to be used in testing the branching journey: +created 26 March 2025 +testing: week commencing 31 March 2025 */ module.exports = { - highestPageId: 6, - action: 'gogogo', - publish: 'GOV.UK', - authentication: 'email', - payments: 'no', + /* Dummy form settings */ + formTitle: 'Tell us about a complaint, concern or error', + status: 'Draft', + + // Form tasks + isQuestionsComplete: 'no', + // checkAnswersDeclaration + isDeclarationComplete: 'no', + // confirmationNext + isConfirmationComplete: 'no', + // formsEmail + isSubmissionEmailComplete: 'no', + // confirmationCode + isConfirmationCodeComplete: 'no', + // privacyInformation + isPrivacyInformationComplete: 'no', + // supportDetails - emailSupport, phoneSupport, onlineSupportLink, onlineSupportText + isSupportDetailsComplete: 'no', + // makeFormLive + isFormLive: 'no', + + // Form questions + highestPageId: 7, pages: [ { - 'long-title': 'What type of animal is your pet?', - 'short-title': 'Animal type', - 'hint-text': 'For example a bird, cat, dog.', - type: 'text', - pageIndex: '0' + pageIndex: '0', + type: 'select', + 'long-title': 'Which of these do you want to do today?', + 'item-list': [ + "Report an error", + "Make a complaint", + "Raise a concern" + ], + 'listSettings': [ + "oneOption" + ], + 'additional-guidance': 'No', + 'questionSaved': 'Yes' + }, + { + pageIndex: '1', + type: 'select', + 'long-title': 'What does your complaint or concern relate to?', + 'item-list': [ + "Service", + "Access", + "Availability", + "Something else" + ], + 'listSettings': [ + "oneOption" + ], + 'additional-guidance': 'No', + 'questionSaved': 'Yes' }, { - 'long-title': 'What is the name of your pet?', - 'short-title': 'Pet name', + pageIndex: '2', type: 'text', - pageIndex: '1' + input: "multi-line-input", + 'long-title': 'Please give full details of your complaint or concern', + 'additional-guidance': 'No', + 'questionSaved': 'Yes' }, { - 'long-title': 'Where are you travelling to?', - 'short-title': 'Destination', - 'hint-text': 'For example Lisbon, Portugal', + pageIndex: '3', + type: 'select', + 'long-title': 'Have you contacted us about this before?', + 'item-list': [ + "Yes", + "No" + ], + 'listSettings': [ + "oneOption" + ], + 'additional-guidance': 'No', + 'questionSaved': 'Yes' + }, + { + pageIndex: '4', type: 'text', - pageIndex: '2' + input: "single-line-input", + 'long-title': 'What were you trying to do when the error happend?', + 'additional-guidance': 'No', + 'questionSaved': 'Yes' }, { - 'long-title': 'What date do you travel?', - 'short-title': 'Date', - 'hint-text': 'For example 27 3 2007', - type: 'date', - pageIndex: '3' + pageIndex: '5', + type: 'text', + input: "multi-line-input", + 'long-title': 'Please tell us what happened when the error occurred', + 'additional-guidance': 'No', + 'questionSaved': 'Yes' }, { - 'long-title': 'How are you travelling?', - 'short-title': 'Transport type', - 'hint-text': 'For example plane, train, car.', + pageIndex: '6', type: 'text', - pageIndex: '4' + input: "multi-line-input", + 'long-title': 'What did you do, if anything, to work around the error?', + 'additional-guidance': 'No', + "questionOptional": [ + "questionOptional" + ], + 'questionSaved': 'Yes' }, { - 'long-title': 'How many pets do you have?', - 'short-title': 'Number of pets', - type: 'number', - pageIndex: '5' + pageIndex: '7', + type: 'select', + 'long-title': 'How would you rate your overall experience of using the service?', + 'item-list': [ + "Very poor", + "Poor", + "Neutral", + "Good", + "Very good" + ], + 'listSettings': [ + "oneOption" + ], + 'additional-guidance': 'No', + 'questionSaved': 'Yes' } - ], - status: 'Draft', - confirmationTitle: 'Your form has been submitted', - checkAnswersTitle: 'Check your answers before submitting your form', - formTitle: 'Take your pet abroad', - isQuestionsComplete: 'no' + ] } diff --git a/app/data/returning-session-data-defaults.js b/app/data/returning-session-data-defaults.js index 7bfc19d3..56c30586 100644 --- a/app/data/returning-session-data-defaults.js +++ b/app/data/returning-session-data-defaults.js @@ -1,28 +1,17 @@ /* -Provide default values for user session data. These are automatically added -via the `autoStoreData` middleware. Values will only be added to the -session if a value doesn't already exist. This may be useful for testing -journeys where users are returning or logging in to an existing application. - -============================================================================ - -Example usage: - -"full-name": "Sarah Philips", - -"options-chosen": [ "foo", "bar" ] - -============================================================================ +This data is for a dummy form - it was previously used in earlier rounds of testing +Not all the structure of the questions will work and may cause some errors throughout the prototype */ module.exports = { + /* Dummy form settings */ + formTitle: 'Amendment form: redundancy claim for holiday pay', + status: 'Draft', + + // Form questions highestPageId: 6, - action: 'gogogo', - publish: 'GOV.UK', - authentication: 'email', - payments: 'no', pages: [ { intro: 'This is the intro', @@ -80,10 +69,5 @@ module.exports = { type: 'number', pageIndex: '7' } - ], - status: 'Draft', - confirmationTitle: 'Your form has been submitted', - checkAnswersTitle: 'Check your answers before submitting your form', - formTitle: 'Amendment form: redundancy claim for holiday pay', - isQuestionsComplete: 'no' + ] } diff --git a/app/data/session-data-defaults.js b/app/data/session-data-defaults.js index 95a505bc..779a12a1 100644 --- a/app/data/session-data-defaults.js +++ b/app/data/session-data-defaults.js @@ -19,55 +19,86 @@ Example usage: module.exports = { - // Insert values here + // Account settings + defaultUser: 'Firstname Ipsum', - highestPageId: 0, - action: '', - publish: 'GOV.UK', + // Group settings + defaultGroup: 'Departmental contact forms', + + // Default form data and settings authentication: 'email', payments: 'no', + publish: 'GOV.UK', + + // Placeholders to avoid errors + // Form questions + highestPageId: 0, pages: [], + // Form status status: 'Draft', - confirmationTitle: 'Your form has been submitted', + // Button actions value - used for ‘continue’, ‘save’, ‘delete’ or any other secondary grey button action + action: '', + + /* STATIC CONTENT + ================= */ + + // Check your answers page checkAnswersTitle: 'Check your answers before submitting your form', + // Confirmation page + confirmationTitle: 'Your form has been submitted', + /* Answer type hints and input type content */ + + // Person name personNameQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your name?’', personNameHintHint: 'You can add a short hint to help people answer the question. For example, you might need to ask people to enter their name as it’s written on an official document such as a passport or driving licence.', personNameInputTypeTitle: 'Name fields', + // Company name companyNameQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s the name of the organisation?’', companyNameHintHint: 'You can add a short hint to help people answer the question. For example, you might need to ask people to enter the registered name of their company.', + // Email emailQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your email address?’', emailHintHint: 'You could use hint text to tell people how you’ll use their email address. For example, ‘We’ll only use your email address to contact you about your application.’', + // Telephone phoneQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your phone number?’', phoneHintHint: 'You can add a short hint to help people answer the question. For example, ‘You can provide either a home or mobile phone number.’', + // National Insurance number (NINo) ninoQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your National Insurance number?’', ninoHintHint: 'You can add a short hint to help people answer the question. For example, ‘It’s on your National Insurance card, benefit letter, payslip or P60. For example, QQ 12 34 56 C.’', + // Address addressQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your address?’', addressHintHint: 'You could use hint text to tell people how you’ll use their address. For example, ‘We’ll send your licence to this address.’', addressInputTypeTitle: 'Address type', - dobQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your date of birth?’', - dobHintHint: 'You can add a short hint to help people answer the question. For a date of birth question you could use ‘For example, 27 3 1998’.', + // Date dateQuestionHint: 'Ask the question the way you would in person. For example, ‘What date was your passport issued?’', dateHintHint: 'You can add a short hint to help people answer the question. For a date question you could use ‘For example, 27 3 2007’.', + + // Date of birth (DOB) + dobQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your date of birth?’', + dobHintHint: 'You can add a short hint to help people answer the question. For a date of birth question you could use ‘For example, 27 3 1998’.', dateOfBirthInputTypeTitle: 'Date of birth', + // Selection - radio, checkbox or autocomplete (build only) selectionOneOptionQuestionHint: 'Ask the question the way you would in person. For example, ‘What country do you live in?’', selectionOneOptionHintHint: 'You can add a short hint to help people answer the question. For a question where people can only select one answer you might want to use ‘Select one option’.', selectionMultipleOptionsQuestionHint: 'Ask the question the way you would in person. For example, ‘Which of these countries have you lived in?’', selectionMultipleOptionsHintHint: 'You can add a short hint to help people answer the question. For a question where people can select more than one answer you might want to use ‘Select all that apply’.', + // Number numberQuestionHint: 'Ask the question the way you would in person. For example, ‘How many holiday days do you get a year?’', numberHintHint: 'You can add a short hint to help people answer the question. For example, ‘Do not include bank holidays’.', + // Text - single line textSingleLineQuestionHint: 'Ask the question the way you would in person. For example, ‘What’s your reference number?’', textSingleLineHintHint: 'You can add a short hint to help people answer the question. For example, you could say what format the answer should be in or where to find it.', + // Textarea - multiple line textMultipleLinesQuestionHint: 'Ask the question the way you would in person. For example, ‘Why do you want to apply for this role?’', textMultipleLinesHintHint: 'You can add a short hint to help people answer the question. For example, you could give a bit more detail about the information you need.', textLengthInputTypeTitle: 'Length' diff --git a/app/routes.js b/app/routes.js index 5761a4da..7a1a70e4 100644 --- a/app/routes.js +++ b/app/routes.js @@ -90,36 +90,24 @@ router.use('/form-designer/*', function (req, res, next) { Create a new form ================= */ -// Middleware name your form -router.use('/form-designer/name-your-form', function (req, res, next) { - +// Name your form - GET +router.get('/form-designer/name-your-form', function (req, res) { // get the previous page URL var previousPage = req.session.data.referer // set the default back link var previousPageLink = `your-form` - var previousPageText = 'Back to create a form' + var previousPageText = 'Back to create your form' - if (previousPage) { + // if user is creating a ‘new’ form we should change the back link + if (previousPage?.includes('your-forms')) { // set the GOV.UK Forms home back link - if (previousPage.includes('your-forms')) { - previousPageLink = `your-forms` - previousPageText = 'Back to your forms' - } + previousPageLink = `your-forms` + previousPageText = 'Back to ' + (req.session.data.defaultGroup || 'your forms' ) } - - // make back link available in the view - req.session.data.previousPageLink = previousPageLink - req.session.data.previousPageText = previousPageText - - next(); -}) - -// Name your form - GET -router.get('/form-designer/name-your-form', function (req, res) { return res.render('form-designer/name-your-form', { - previousPageText: req.session.data.previousPageText, - previousPageLink: req.session.data.previousPageLink + previousPageText, + previousPageLink }) }) @@ -144,11 +132,6 @@ router.post('/form-designer/name-your-form', function (req, res) { if(containsErrors) { res.render('form-designer/name-your-form', { errors, errorList, containsErrors }) } else { - - // remove temporary back link details - req.session.data.previousPageLink = undefined - req.session.data.previousPageText = undefined - // set a success message for saving req.session.data.successMessage = 'Your form name has been saved' res.redirect('your-form') @@ -204,8 +187,8 @@ router.get('/form-designer/your-form', function (req, res) { } return res.render('form-designer/your-form', { - successMessage: successMessage, - sections: sections + successMessage, + sections }) }) @@ -504,26 +487,17 @@ Managing additional pages in a form // Route used to check Declaration is complete - Check your answers (CYA) router.post('/form-designer/pages/check-answers/edit', function (req, res) { - const action = req.session.data.action - req.session.data.action = undefined - + const errors = {}; var pageId = parseInt(req.params.pageId, 10) var pageIndex = pageId var pageData = req.session.data.pages[pageIndex] + var { checkAnswersDeclaration, isDeclarationComplete } = req.session.data - const errors = {}; - const complete = req.session.data.isDeclarationComplete - const declarationContent = req.session.data.checkAnswersDeclaration - - // content to display in notification banners - var saved = 'Your declaration has been saved' - var savedAndComplete = 'Your declaration has been saved and marked as complete' - - // if no selection made, then throw an error - if (!complete || !complete.length) { - errors['isDeclarationComplete'] = { - text: 'Select yes if you want to mark this task as complete', - href: "#isDeclarationComplete" + // if trying to mark as complete while having too many characters, then throw an error + if ((checkAnswersDeclaration.length > 2000) && (isDeclarationComplete == 'yes')) { + errors['checkAnswersDeclaration'] = { + text: 'The declaration cannot be longer than 2,000 characters', + href: "#check-answers-declaration" } } @@ -533,16 +507,7 @@ router.post('/form-designer/pages/check-answers/edit', function (req, res) { // 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 (action === 'update') { - // set a success message for saving - req.session.data.successMessage = saved - return res.render('form-designer/pages/check-answers/edit', { - pageId: pageId, - pageIndex: pageIndex, - pageData: pageData, - successMessage: saved - }) - } else if(containsErrors) { + if(containsErrors) { return res.render('form-designer/pages/check-answers/edit', { pageId: pageId, pageIndex: pageIndex, @@ -552,37 +517,28 @@ router.post('/form-designer/pages/check-answers/edit', function (req, res) { containsErrors }) } else { - if(complete === 'yes') { + if(isDeclarationComplete === 'yes') { // set a success message for saving - req.session.data.successMessage = savedAndComplete + req.session.data.successMessage = 'Your declaration has been saved and marked as complete' } else { // set a success message for saving - req.session.data.successMessage = saved + req.session.data.successMessage = 'Your declaration has been saved' } + req.session.data.isDeclarationComplete = isDeclarationComplete return res.redirect('../../your-form') } }) // Route used to check What happens next (WHN) content has been added router.post('/form-designer/pages/confirmation/edit', function (req, res) { - const action = req.session.data.action - req.session.data.action = undefined - - var pageId = parseInt(req.params.pageId, 10) - var pageIndex = pageId - var pageData = req.session.data.pages[pageIndex] - const errors = {}; - const whatHappensNext = req.session.data.confirmationNext - - // content to display in notification banners - var saved = 'Your information about what happens next has been saved' + const { whatHappensNext } = req.session.data // if no selection made, then throw an error if (!whatHappensNext || !whatHappensNext.length) { - errors['confirmationNext'] = { + errors['whatHappensNext'] = { text: 'Enter some information about what happens next', - href: "#confirmationNext" + href: "#what-happens-next" } } @@ -593,24 +549,10 @@ router.post('/form-designer/pages/confirmation/edit', function (req, res) { 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/confirmation/edit', { - pageId: pageId, - pageIndex: pageIndex, - pageData: pageData, - errors, - errorList, - containsErrors - }) - } else if (action === 'update') { - return res.render('form-designer/pages/confirmation/edit', { - pageId: pageId, - pageIndex: pageIndex, - pageData: pageData, - successMessage: saved - }) + return res.render('form-designer/pages/confirmation/edit', { errors, errorList, containsErrors }) } else { // set a success message for saving - req.session.data.successMessage = saved + req.session.data.successMessage = 'Your information about what happens next has been saved' return res.redirect('../../your-form') } }) @@ -641,17 +583,73 @@ router.get('/form-designer/pages/:pageId/view', function (req, res) { // Routing for new-tab page previews, set to a specific page router.post('/form-designer/preview/:pageId(\\d+)', function (req, res) { + // this is used to check if the user has clicked ‘change’ link on the CYA screen - we add a URL query ‘cya=true’ var cya = req.session.data.cya - req.session.data.cya = undefined + // this clears the temporary URL query so it can be reused on another ‘change’ link + req.session.data.cya = undefined + var pageId = req.params.pageId var pageIndex = parseInt(pageId) const isLastQuestionPage = pageIndex === (req.session.data.pages.length - 1) + var pages = req.session.data.pages + var pageAnswer = req.session.data[pageIndex] + + var pagesCYA = req.session.data.pagesCYA + + if (!pagesCYA) { + pagesCYA = [] + } + + // set variable for the next page, with default + var nextPage = `${pageIndex + 1}` + + // for all pages in the form + for (let index = 0; index < pages.length; index++) { + const page = pages[index]; + // get the current page + if (page.pageIndex == pageIndex) { + // if current page has routing attribute + if (page.routing) { + if (page.routing.answer != pageAnswer) { + // if the answer is being changed and doesn’t skip remove the CYA change link function to force user to go through the rest of the journey + cya = 'false' + } + if (page.routing.answer == pageAnswer) { + // override the nextPage to the one in routing + nextPage = page.routing.skipTo + } + if (page.routing.thenSkipTo) { + // override the nextPage to the ‘Route for any other answer’ + nextPage = page.routing.thenSkipTo + } + } + // check if we are changing an answer + if (cya !== 'true') { + // check current page against pagesCYA array - if it exists don’t add it + var pageExists = 'false'; + for (let andex = 0; andex < pagesCYA.length; andex++) { + const answeredPage = pagesCYA[andex]; + if (answeredPage.pageIndex == page.pageIndex) { + pageExists = 'true' // the page exists + } + } + // ignore existing pages + if (pageExists !== 'true') { + // add this answered question to our check your answers page + pagesCYA.push(page) + } + } + } + } + // set the session data so we can use it + req.session.data.pagesCYA = pagesCYA + // if last question in form OR user clicked on change link from CYA, then go to CYA - if(isLastQuestionPage || cya === 'true') { + if(isLastQuestionPage || nextPage == 'cya' || cya === 'true') { return res.redirect('check-answers') } else { - return res.redirect(`${pageIndex + 1}`) + return res.redirect(nextPage) } }) @@ -1025,4 +1023,7 @@ router.use('/pages', require('./views/form-designer/pages/\_routes')) /* Use the routes file in product-pages for groups and members routes */ router.use('/product-pages', require('./views/product-pages/\_routes')) +/* Use the routes file in question-routes for adding routing and branching to questions */ +router.use('/question-routes', require('./views/form-designer/question-routes/\_routes')) + module.exports = router \ No newline at end of file diff --git a/app/views/form-builder-prototypes.html b/app/views/form-builder-prototypes.html index aac8054d..5dacb604 100644 --- a/app/views/form-builder-prototypes.html +++ b/app/views/form-builder-prototypes.html @@ -39,19 +39,11 @@

Admin prototype


- Amendment form: redundancy claim for holiday pay return journey (Insolvency Service first form) -

-

- - View incomplete form return journey prototype -

- -

- Take your pet abroad return journey (testing form) + Tell us about a complaint or concern (testing form)

- View completed form return journey prototype + View an existing form journey


diff --git a/app/views/form-designer/pages/_routes.js b/app/views/form-designer/pages/_routes.js index 85cd15bb..f136b80a 100644 --- a/app/views/form-designer/pages/_routes.js +++ b/app/views/form-designer/pages/_routes.js @@ -414,21 +414,19 @@ router.post('/form-designer/pages/:pageId(\\d+)/edit', function (req, res) { const errors = {}; - if (!pageData['long-title']) { - const title = req.session.data['long-title'] - - // if no question text given, then throw an error - if (!title || !title.length) { - errors['long-title'] = { - text: 'Enter a question', - href: "#long-title" - } - // otherwise add question text to pageData - } else { - pageData['long-title'] = req.session.data['long-title'] + var title = req.session.data['long-title'] + + // if no question text given, then throw an error + if (!title || !title.length) { + errors['long-title'] = { + text: 'Enter a question', + href: "#long-title" } - req.session.data['long-title'] = undefined + // otherwise add question text to pageData + } else { + pageData['long-title'] = req.session.data['long-title'] } + req.session.data['long-title'] = undefined // if hint text is added, add it to pageData if (req.session.data['hint-text']) { diff --git a/app/views/form-designer/pages/check-answers/edit.html b/app/views/form-designer/pages/check-answers/edit.html index c1b5f21a..c026ff15 100644 --- a/app/views/form-designer/pages/check-answers/edit.html +++ b/app/views/form-designer/pages/check-answers/edit.html @@ -18,14 +18,6 @@ {% block content %}
- - {% if successMessage %} - {{ govukNotificationBanner({ - type: 'success', - text: successMessage - }) }} - {% endif %} -
{% if containsErrors %} @@ -65,20 +57,21 @@

Example

{{ govukCharacterCount({ name: "checkAnswersDeclaration", - id: "checkAnswersDeclaration", + id: "check-answers-declaration", maxlength: 2000, value: data['checkAnswersDeclaration'], label: { text: "Enter a declaration for people to agree to (optional)", classes: "govuk-label--m" - } + }, + errorMessage: { text: errors['checkAnswersDeclaration'].text } if errors['checkAnswersDeclaration'].text }) }} {% if data.status === 'Draft' %} {{ govukRadios({ - classes: "govuk-radios", - idPrefix: "isDeclarationComplete", + idPrefix: "is-declaration-complete", name: "isDeclarationComplete", + classes: "govuk-radios", fieldset: { legend: { text: "Do you want to mark this task as complete?", @@ -105,8 +98,6 @@

Example

}) }} {% endif %} - - {{ govukButton({ text: "Save and continue", name: "action", @@ -116,11 +107,4 @@

Example

-{% endblock %} - -{% block pageScripts %} - -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/pages/check-question.html b/app/views/form-designer/pages/check-question.html index aaa04d68..a5f23d0f 100644 --- a/app/views/form-designer/pages/check-question.html +++ b/app/views/form-designer/pages/check-question.html @@ -289,6 +289,24 @@

Guidance

{% endif %} + {% if (pageData.type === 'select') and ('oneOption' in pageData.listSettings) %} +

Routes

+

+ {% if pageData.routing %} + This question has routes: Question {{ pageIndex|int + 1 }}’s routes + {% else %} + If you need people to skip some questions based on their answer to this question, you can add a question route. + {% endif %} +

+
+ {% elif pageData.routing and (pageData.routing.noAnswer) %} +

Routes

+

+ People will skip to question {{ pageData.routing.thenSkipTo|int + 1 }} after this question because of Question {{ pageData.routing.baseQuestion|int + 1 }}’s routes. +

+
+ {% endif %} +
@@ -299,12 +317,12 @@

Guidance

value: "update" }) }} {# Grey CTA - Save and preview question #} - {{ govukButton({ + {# {{ govukButton({ classes: "govuk-button--secondary", text: "Save and preview", name: "action", value: "savePreview" - }) }} + }) }} #}
{% if editingExistingQuestion === 'Yes' %} @@ -322,15 +340,12 @@

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/confirmation/edit.html b/app/views/form-designer/pages/confirmation/edit.html index fe4c81b9..d0b5cb86 100644 --- a/app/views/form-designer/pages/confirmation/edit.html +++ b/app/views/form-designer/pages/confirmation/edit.html @@ -18,14 +18,6 @@ {% block content %}
- - {% if successMessage %} - {{ govukNotificationBanner({ - type: 'success', - text: successMessage - }) }} - {% endif %} -
{% if containsErrors %} @@ -38,14 +30,8 @@ {{ data.formTitle or '[formTitle]' }}

{{ pageTitle }}

- {# - Every field id is prefixed with a unique page id. - So we can have separate configurations for every page. - #} - {% set pagePrefix = "p" + pageId + "-" %} -

- Add some information to tell people what will happen after they've submitted their form, and when - so they know what to expect. + Add some information to tell people what will happen after they’ve submitted their form, and when - so they know what to expect.

Example

@@ -58,7 +44,7 @@

Example

  • - shown to people when they've completed and submitted a form + shown to people when they’ve completed and submitted a form
  • included in an email confirmation, if they choose to receive this @@ -69,19 +55,62 @@

    Example

    The optional email confirmation will also include the contact details you provide for the form, and the date and time of submission. It will not include a copy of their answers.

    + {{ govukInsetText({ + text: "GOV.UK Forms adds a unique reference number to the confirmation page and optional email confirmation. This will also be included in submission emails sent to your processing email address." + }) }} + {{ govukCharacterCount({ - name: "confirmationNext", - id: "confirmationNext", - maxlength: 2000, - value: data['confirmationNext'], + id: "what-happens-next", + name: "whatHappensNext", label: { text: "Enter some information to tell people what will happen next", classes: "govuk-label--m" }, - errorMessage: { text: errors['confirmationNext'].text } if errors['confirmationNext'].text + maxlength: 2000, + value: data['whatHappensNext'], + errorMessage: { text: errors['whatHappensNext'].text } if errors['whatHappensNext'].text }) }} - + {% set formatHelpHTML -%} + {# Links and URLs #} +

    Links and URLs

    +

    + To add a link, use square brackets [ ] around the link text, and round brackets ( ) around the full URL. Make sure there are no spaces between the two sets of brackets. For example: +

    + {{ govukInsetText({ + text: "[Link text](https://www.gov.uk/link-text-url)" + }) }} + {# Bulleted lists #} +

    Bulleted lists

    +

    + To add bullet points, start each item with * (asterisk) or - (dash). Make sure there is one space after the asterisk or dash. +

    +

    + Leave one empty line before adding the first bullet point and another after the last bullet point. For example: +

    + {{ govukInsetText({ + html: "* First bullet point
    + * Second bullet point
    + * Third bullet point" + }) }} + {# Numbered lists #} +

    Numbered lists

    +

    + Use numbers for each list item, followed by a full stop. Make sure there is one space after the full stop. +

    +

    + Leave one empty line before adding the first list item and another after the last list item. For example: +

    + {{ govukInsetText({ + html: "1. First item
    + 2. Second item
    + 3. Third item" + }) }} + {%- endset %} + {{ govukDetails({ + summaryText: "Formatting help", + html: formatHelpHTML + }) }} {{ govukButton({ text: "Save and continue", @@ -93,10 +122,3 @@

    Example

{% endblock %} - -{% block pageScripts %} - -{% endblock %} diff --git a/app/views/form-designer/pages/edit-answer-type.html b/app/views/form-designer/pages/edit-answer-type.html index de8065bf..1f694af7 100644 --- a/app/views/form-designer/pages/edit-answer-type.html +++ b/app/views/form-designer/pages/edit-answer-type.html @@ -110,14 +110,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..8213d23f 100644 --- a/app/views/form-designer/pages/edit-select-question.html +++ b/app/views/form-designer/pages/edit-select-question.html @@ -2,7 +2,7 @@ {% set pageTitle = "What's your question?" %} -{% set answerType = pageData['type']|capitalize %} +{% set answerType = pageData['type'] | capitalize %} {% if pageData['type'] === 'select' %} {% set answerType = 'Selection from a list' %} @@ -16,7 +16,8 @@ {% endif %} {% block pageTitle %} - {{ "Error: " if containsErrors }}{{ pageTitle }} - GOV.UK Forms + {{ "Error: " if containsErrors }}{{ pageTitle }} + - GOV.UK Forms {% endblock %} {% block beforeContent %} @@ -27,23 +28,23 @@ {% endblock %} {% block content %} -
-
- -
- {% if containsErrors %} +
+
+ + {% if containsErrors %} {{ govukErrorSummary({ titleText: "There is a problem", errorList: errorList }) }} - {% endif %} + {% endif %} - Question {{ pageId | int + 1 }} + Question + {{ pageId | int + 1 }} - {% set namePrefix = "pages[" + pageIndex + "]" %} + {% set namePrefix = "pages[" + pageIndex + "]" %} - - {{ govukInput({ + + {{ govukInput({ label: { text: pageTitle, classes: "govuk-label--l", @@ -58,18 +59,15 @@ errorMessage: { text: errors['long-title'].text } if errors['long-title'].text }) }} - {{ govukButton({ + {{ govukButton({ text: "Continue" }) }} - - {# If we are not sure what the back link is going to don’t show the bottom link #} - {% if previousPageText !== 'Back' %} -

- - {{ previousPageText }} - -

- {% endif %} + +

+ + Back to your questions + +

@@ -77,8 +75,8 @@ {% endblock %} {% block pageScripts %} - -{% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/pages/edit-settings.html b/app/views/form-designer/pages/edit-settings.html index 029f1882..5acb9d81 100644 --- a/app/views/form-designer/pages/edit-settings.html +++ b/app/views/form-designer/pages/edit-settings.html @@ -287,16 +287,12 @@

{{pageTitle}}

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/edit.html b/app/views/form-designer/pages/edit.html index 8fdde3e7..275f849b 100644 --- a/app/views/form-designer/pages/edit.html +++ b/app/views/form-designer/pages/edit.html @@ -2,7 +2,7 @@ {% set pageTitle = 'Edit question' %} -{% set answerType = pageData['type']|capitalize %} +{% set answerType = pageData['type'] | capitalize %} {% if pageData['type'] === 'personName' %} {% set questionHint = data.personNameQuestionHint %} {% set hintHint = data.personNameHintHint %} @@ -54,7 +54,8 @@ {% endif %} {% block pageTitle %} - {{ "Error: " if containsErrors }}{{ pageTitle }} - GOV.UK Forms + {{ "Error: " if containsErrors }}{{ pageTitle }} + - GOV.UK Forms {% endblock %} {% block beforeContent %} @@ -68,22 +69,23 @@
-
+ - {% if containsErrors %} - {{ govukErrorSummary({ + {% if containsErrors %} + {{ govukErrorSummary({ titleText: "There is a problem", errorList: errorList }) }} - {% endif %} + {% endif %} - Question {{ pageId | int + 1 }} -

{{pageTitle}}

+ Question + {{ pageId | int + 1 }} +

{{pageTitle}}

- {% set namePrefix = "pages[" + pageIndex + "]" %} + {% set namePrefix = "pages[" + pageIndex + "]" %} - - {{ govukInput({ + + {{ govukInput({ label: { text: "Question text", classes: "govuk-label--m" @@ -97,10 +99,10 @@

{{pageTitle}}

errorMessage: { text: errors['long-title'].text } if errors['long-title'].text }) }} -
+
- - {{ govukTextarea({ + + {{ govukTextarea({ label: { text: "Hint text (optional)", classes: "govuk-label--m" @@ -113,10 +115,10 @@

{{pageTitle}}

value: pageData['hint-text'] }) }} -
+
- - {{ govukRadios({ + + {{ govukRadios({ classes: "govuk-radios--inline", name: "additional-guidance", fieldset: { @@ -143,11 +145,11 @@

{{pageTitle}}

errorMessage: { text: errors['additional-guidance'].text } if errors['additional-guidance'].text }) }} - - {% if pageData['type'] != 'select' %} -
+ + {% if pageData['type'] != 'select' %} +
- {{ govukCheckboxes({ + {{ govukCheckboxes({ idPrefix: "questionOptional", name: "questionOptional", fieldset: { @@ -170,22 +172,19 @@

{{pageTitle}}

} ] }) }} - {% endif %} + {% endif %} - {{ govukButton({ + {{ govukButton({ text: "Continue", 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 }} - -

- {% endif %} + +

+ + Back to your questions + +

@@ -193,8 +192,8 @@

{{pageTitle}}

{% endblock %} {% block pageScripts %} - -{% endblock %} + +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/partials/status-draft-form.html b/app/views/form-designer/partials/status-draft-form.html index 55ebafa0..5ede1667 100644 --- a/app/views/form-designer/partials/status-draft-form.html +++ b/app/views/form-designer/partials/status-draft-form.html @@ -12,7 +12,7 @@

{{pageTitle}}

{% if data.pages.length %} -

+

Preview this form @@ -20,11 +20,11 @@

{{pageTitle}}

{% endif %}

- You have completed {{sections}} of 9 tasks. + You have completed {{ sections }} of 10 tasks.

- Create your form + 1. Create your form

{# SET STATUS OF THE FORM TITLE #} @@ -32,7 +32,7 @@

{% set formNameStatusText = 'Completed' %} {% else %} {% set formNameStatusTag = 'govuk-tag--blue' %} - {% set formNameStatusText = 'Not yet started' %} + {% set formNameStatusText = 'Not started' %} {% endif %} {% set htmlFormTitle %} {% if data['formTitle'] %} @@ -52,7 +52,7 @@

{% set questionStatusText = 'In progress' %} {% else %} {% set questionStatusTag = 'govuk-tag--blue' %} - {% set questionStatusText = 'Not yet started' %} + {% set questionStatusText = 'Not started' %} {% endif %} {% set htmlAddedQuestions %} {% if data.isQuestionsComplete === 'yes' %} @@ -67,12 +67,12 @@

{# SET STATUS OF DECLARATION #} {% if data.isDeclarationComplete === 'yes' %} {% set declarationStatusText = 'Completed' %} -{% elif data.isDeclarationComplete === 'no' and data.checkAnswersDeclaration != '' %} +{% elif (data.isDeclarationComplete === 'no') and data.checkAnswersDeclaration %} {% set declarationStatusTag = 'govuk-tag--light-blue' %} {% set declarationStatusText = 'In progress' %} {% else %} {% set declarationStatusTag = 'govuk-tag--blue' %} - {% set declarationStatusText = 'Not yet started' %} + {% set declarationStatusText = 'Not started' %} {% endif%} {% set htmlDeclaration %} {% if data.isDeclarationComplete === 'yes' %} @@ -89,7 +89,7 @@

{% set whatHappensNextStatusText = 'Completed' %} {% else %} {% set whatHappensNextStatusTag = 'govuk-tag--blue' %} - {% set whatHappensNextStatusText = 'Not yet started' %} + {% set whatHappensNextStatusText = 'Not started' %} {% endif%} {% set htmlWhatHappensNext %} {% if data.confirmationNext %} @@ -147,11 +147,11 @@

{% if data.paymentLink %} {% set paymentLinkStatusText = 'Completed' %} {% else %} - {% set paymentLinkStatusTag = 'govuk-task-list__status--cannot-start-yet' %} + {% set paymentLinkStatusTag = 'govuk-tag--grey' %} {% set paymentLinkStatusText = 'Optional' %} {% endif%} -

Optional tasks

+

Optional task

{{ govukTaskList({ idPrefix: "payment-link", items: [ @@ -161,8 +161,10 @@

Optional tasks

}, href: "payment/add-payment-link", status: { - text: paymentLinkStatusText, - classes: paymentLinkStatusTag if not data.paymentLink + tag: { + text: paymentLinkStatusText, + classes: paymentLinkStatusTag if not data.paymentLink + } } } ] @@ -180,7 +182,7 @@

Optional tasks

{% endif %} {% if not (data.formsEmail) %} {% set submissionEmailStatusTag = 'govuk-tag--blue' %} - {% set submissionEmailStatusText = 'Not yet started' %} + {% set submissionEmailStatusText = 'Not started' %} {% elif (data.formsEmail and (not data.confirmationCode)) or data.currentFormsEmail %} {% set submissionEmailStatusTag = 'govuk-tag--light-blue' %} {% set submissionEmailStatusText = 'In progress' %} @@ -213,7 +215,7 @@

Optional tasks

{% set confirmationCodeStatusHint = '' %} {% elif data.formsEmail and not data.confirmationCode %} {% set confirmationCodeStatusTag = 'govuk-tag--blue' %} - {% set confirmationCodeStatusText = 'Not yet started' %} + {% set confirmationCodeStatusText = 'Not started' %} {% else %} {% set confirmationCodeStatusText = 'Completed' %} {% endif%} @@ -228,7 +230,7 @@

Optional tasks

{% endset %}

- Set email address for completed forms +2. Set up how you get completed forms

{{ govukTaskList({ idPrefix: "processing-email", @@ -261,6 +263,25 @@

] }) }} +

Optional task

+{{ govukTaskList({ + idPrefix: "csv-submission", + items: [ + { + title: { + text: "Get completed forms as CSV files" + }, + href: "#", + status: { + tag: { + text: 'Optional', + classes: 'govuk-tag--grey' + } + } + } + ] +}) }} + {# SET STATUS OF PRIVACY INFORMATION #} {# Refactor this logic outside of class attribute #} @@ -268,7 +289,7 @@

{% set privacyInformationStatusText = 'Completed' %} {% else %} {% set privacyInformationStatusTag = 'govuk-tag--blue' %} - {% set privacyInformationStatusText = 'Not yet started' %} + {% set privacyInformationStatusText = 'Not started' %} {% endif%} {% set htmlPrivacyInformation %} {% if data.privacyInformation %} @@ -286,7 +307,7 @@

{% set supportDetailsStatusText = 'Completed' %} {% else %} {% set supportDetailsStatusTag = 'govuk-tag--blue' %} - {% set supportDetailsStatusText = 'Not yet started' %} + {% set supportDetailsStatusText = 'Not started' %} {% endif%} {% set htmlSupportDetails %} {% if data.supportDetails %} @@ -299,7 +320,7 @@

{% endset %}

- Provide privacy and contact details +3. Provide privacy and contact details

{{ govukTaskList({ idPrefix: "processing-email", @@ -331,7 +352,7 @@

{% set formVersionStatusText = 'Completed' %} {% elif sections >= 6 %} {% set formVersionStatusTag = 'govuk-tag--blue' %} - {% set formVersionStatusText = 'Not yet started' %} + {% set formVersionStatusText = 'Not started' %} {% else %} {% set formVersionStatusTag = 'govuk-task-list__status--cannot-start-yet' %} {% set formVersionStatusText = 'Cannot start yet' %} @@ -348,7 +369,7 @@

{% endset %}

- Make your form live +4. Make your form live

{% if data['journey'] and data['journey'] == 'groupAdminTasks' %} @@ -370,15 +391,24 @@

{% else %} {{ govukTaskList({ - idPrefix: "processing-email", + idPrefix: "make-live", items: [ + { + title: { + text: 'Share a preview of your draft form' + }, + href: '#', + status: { + html: 'Not started' + } + }, { title: { text: "Make your form live" }, hint: { text: formVersionStatusHint - } if sections < 6, + } if formVersionStatusHint !== '' and sections < 6, href: "make-your-form-live" if sections >= 6, status: { html: htmlFormVersion, @@ -393,7 +423,7 @@

{{ govukButton({ text: "Delete draft form", - classes: "govuk-button--warning govuk-!-margin-top-5", + classes: "govuk-button--warning", name: "action", value: "deleteDraft" }) }} 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..d433936b 100644 --- a/app/views/form-designer/partials/your-questions-live-form.html +++ b/app/views/form-designer/partials/your-questions-live-form.html @@ -177,6 +177,51 @@

{{ page['long-title'] }}{{ ' (optional)' i
{{ titleText }}

{% endif %} + + {# now we can add any route that is based on an answer to the question above #} + {% if page.routing.skipTo %} + {% set skipPage = '' %} + {% if page.routing.skipTo == 'cya' %} + {% set skipPage = '“' + data.checkAnswersTitle + '”' %} + {% else %} + {% for item in data.pages %} + {% if (item.pageIndex|int) == (page.routing.skipTo|int) %} + {% set skipPage -%}{{ page.routing.skipTo|int + 1 }}, “{{ item['long-title'] }}”{%- endset %} + {% endif %} + {% endfor %} + {% endif %} +
+
+ Routes +
+
+ If the answer is “{{ page.routing.answer }}” then skip to {{ skipPage }} +
+
+ {% endif %} + {# finally we need to add routing not based on an answer if there is any #} + {% if page.routing.noAnswer %} + {% set skipPage = '' %} + {% if page.routing.thenSkipTo == 'cya' %} + {% set skipPage = '“' + data.checkAnswersTitle + '”' %} + {% else %} + {% for otherRoutePage in data.pages %} + {% if (otherRoutePage.pageIndex|int) == (page.routing.thenSkipTo|int) %} + {% set skipPage -%} + {{ otherRoutePage.pageIndex|int + 1 }}, “{{ otherRoutePage['long-title'] }}” + {%- endset %} + {% endif %} + {% endfor %} + {% endif %} +
+
+ Routes +
+
+ Skip the person to {{ skipPage }} +
+
+ {% endif %}
diff --git a/app/views/form-designer/preview/check-answers.html b/app/views/form-designer/preview/check-answers.html index 892c37c0..4adf57fb 100644 --- a/app/views/form-designer/preview/check-answers.html +++ b/app/views/form-designer/preview/check-answers.html @@ -18,7 +18,7 @@

- {% for page in data.pages -%} + {% for page in data.pagesCYA -%} {% set questionTitle = page["long-title"] or "Page " + page["pageIndex"] %} {% if page['questionOptional'] %} diff --git a/app/views/form-designer/question-routes/_routes.js b/app/views/form-designer/question-routes/_routes.js new file mode 100644 index 00000000..a6493def --- /dev/null +++ b/app/views/form-designer/question-routes/_routes.js @@ -0,0 +1,568 @@ +const govukPrototypeKit = require('govuk-prototype-kit') +const router = govukPrototypeKit.requests.setupRouter() + +/* CREATING A NEW QUESTION ROUTE +================================ */ + +/* Route 1 */ + +// Render question route start +getStartQuestion = 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/question-routes/new-condition', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData + }) +} +router.get('/form-designer/question-routes/new-condition', getStartQuestion) +router.get('/form-designer/question-routes/:pageId(\\d+)/new-condition', getStartQuestion) + +// Create a new question route - button journey +// this POST also creates our ‘pageId’ to use throughout the editing and creating of routes attached to it +postStartQuestion = function (req, res) { + const errors = {} + var routeStartQuestion = req.session.data.routeStartQuestion + var pageIndex = parseInt(routeStartQuestion, 10) + var { pages } = req.session.data + + // If the no question to start the route has been selected, create an error to be displayed to the user + if (!routeStartQuestion && routeStartQuestion !== 0) { + errors.routeStartQuestion = { + text: 'Select the question you want your route to start from', + href: "#routeStartQuestion" + } + } + + /* + set a temporary check variable to hold if the page exists + var yuppityYup = false + we first need to loop through the existing data.pages + for (page in data.pages) + check if the selected page already has a route + if ((page.pageIndex == pageIndex) && (page.routing)) + yuppityYup = true + */ + var yuppityYup = false + for (let index = 0; index < pages.length; index++) { + const element = pages[index]; + if ((parseInt(element.pageIndex, 10)) == pageIndex) { + if (element.routing) { + yuppityYup = true + } + } + } + + // 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(containsErrors) { + res.render('form-designer/question-routes/new-condition', { errors, errorList, containsErrors }) + } else { + // if selected question already has a route we want to take the user to the question routes summary page + if (yuppityYup) { + // tkae user to question routes summary page + res.redirect(`${pageIndex}/routes-summary`) + } else { + // go to add answer and skip to conditions for the route + res.redirect(`${pageIndex}/conditions`) + } + } +} +router.post('/form-designer/question-routes/route-start', postStartQuestion) +router.post('/form-designer/question-routes/:pageId(\\d+)/route-start', postStartQuestion) + +// Render ‘Route 1’ answer and skip to conditions +router.get('/form-designer/question-routes/:pageId(\\d+)/conditions', 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/question-routes/conditions', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData + }) +}) + +// Create ‘Route 1’ - button journey +postConditions = function (req, res) { + const errors = {} + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + var { pages, route1Answer, route1End, action } = req.session.data + + // If the ‘is answered as’ input has not been selected, create an error to be displayed to the user + if (!route1Answer?.length) { + errors.route1Answer = { + text: 'Select the answer to base this route on', + href: "#route-1-answer" + } + } + // If the ‘skip the person’ to input has not been selected, create an error to be displayed to the user + if (!route1End?.length) { + errors.route1End = { + text: 'Select the question or page to skip to', + href: "#route-1-end" + } + } + + // 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(containsErrors) { + res.render('form-designer/question-routes/conditions', { errors, errorList, containsErrors, pageId, pageIndex, pageData }) + } else if (action?.length && (action === 'deleteRoute1')) { + // reset our temporary route session data + req.session.data.routeStartQuestion = undefined + req.session.data.route1Answer = undefined + req.session.data.route1End = undefined + // reset action + req.session.data.action = undefined + /* + we need to redirect the user to the are you sure you want to delete this route page, if the user selects yes on that screen we can start deleting the routes + */ + res.redirect(`are-you-sure?action=` + action) + } else { + /* + we need to loop through our forms questions + for page in req.session.data.pages + find if the routeStart is the same as the current page loop + if page.pageIndex === routeStartQuestion + now we need to check if routing already exists on our base question + if page.routing + we just want to update the existing keys + routing.answer = route1Answer + routing.skipTo = route1End + else + we need to create a new key object for routing + page.push( + routing: { + routeAnswer: route1Answer, + routeEnd: route1End + }) + clear (routeStartQuestion, route1Answer, route1End) + */ + for (let index = 0; index < pages.length; index++) { + const element = pages[index]; + if ((parseInt(element.pageIndex, 10)) == pageIndex) { + if (element.routing) { + element.routing.answer = route1Answer + element.routing.skipTo = route1End + } else { + element.routing = { 'answer': route1Answer, 'skipTo': route1End } + } + } + } + // reset our temporary route session data + req.session.data.routeStartQuestion = undefined + req.session.data.route1Answer = undefined + req.session.data.route1End = undefined + // reset action + req.session.data.action = undefined + // set a success message to declare that ‘route 1’ has been saved + req.session.data.successMessage = "Route 1 has been saved" + // go to question X’s routes summary screen + res.redirect(`routes-summary`) + } +} +router.post('/form-designer/question-routes/route-conditions', postConditions) +router.post('/form-designer/question-routes/:pageId(\\d+)/route-conditions', postConditions) + + +/* Questions routes summary screen */ + +// Render questions routes summary page +router.get('/form-designer/question-routes/:pageId(\\d+)/routes-summary', function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + + // get success message and then clear session data (so it doesn’t hang around) + var successMessage = req.session.data.successMessage + req.session.data.successMessage = undefined + + return res.render('form-designer/question-routes/routes-summary', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + successMessage + }) +}) + +// Start a ‘Route for any other answer’ - suggested question - button journey +router.post('/form-designer/question-routes/:pageId(\\d+)/questions-routes', function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + + // get the suggested question (based on the ‘route 1’ end) + var { pages, suggestedQuestion, action } = req.session.data + + /* + check if delete button is pressed + if action && action == deleteAllRoutes + now we need to find the questions with the route 1 and route for any other answer + and then we can delete these + */ + if (action?.length && (action === 'deleteAllRoutes')) { + // reset action + req.session.data.action = undefined + /* + need to take the user to an are you sure page? + just now it will delete the routes and redirect them to ‘add and edit your questions’ page + */ + // go to form questions list + res.redirect(`are-you-sure`) + } else { + // add the first part of routing to the suggested question + // for (let index = 0; index < pages.length; index++) { + // const element = pages[index]; + // if ((parseInt(element.pageIndex, 10)) == suggestedQuestion) { + // element.routing = { 'noAnswer': 'true' } // add a routing element to the question + // } + // } + // reset the session data for suggestedQuestion + req.session.data.suggestedQuestion = undefined + // reset action + req.session.data.action = undefined + // go to add a secondary route to this question + res.redirect(`${suggestedQuestion}/question-to-skip-to`) + } +}) + + +/* For any other answer route */ + +// Render ‘Route for any other answer’ start question +getRouteOtherAnswer = function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + var routeId = parseInt(req.params.routeQuestion, 10) + var routeData = req.session.data.pages[routeId] + return res.render('form-designer/question-routes/other-answer-route', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + routeId: routeId, + routeData: routeData + }) +} +router.get('/form-designer/question-routes/:pageId(\\d+)/other-answer-route', getRouteOtherAnswer) +router.get('/form-designer/question-routes/:pageId(\\d+)/:routeQuestion(\\d+)/other-answer-route', getRouteOtherAnswer) + +// Start a ‘Route for any other answer’ - custom question - button journey +postRouteOtherAnswerStart = function (req, res) { + const errors = {} + var routeId = parseInt(req.params.routeQuestion, 10) + var routeQuestion = parseInt(req.session.data.routeQuestion, 10) + var { pages } = req.session.data + + /* + we need to check if the routeId (original route question) is the same as the newly chosen one + if routeId !== routeQuestion + we then need to find the routeId page from the form + for page in req.session.data.pages + if page.pageIndex == routeId + finally we can ‘delete’ the routing key object + delete page.routing + */ + if (routeId !== routeQuestion) { + for (let index = 0; index < pages.length; index++) { + const element = pages[index]; + // add routing value with end point to the relevant question + if ((parseInt(element.pageIndex, 10)) == routeId) { + delete element.routing + } + } + } + + // If the no question to start the route has been selected, create an error to be displayed to the user + if (!routeQuestion) { + errors.routeQuestion = { + text: 'Select the question you want to add your route from', + href: "#routeQuestion" + } + } + + // 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(containsErrors) { + res.render('form-designer/question-routes/other-answer-route', { errors, errorList, containsErrors, routeId, routeQuestion }) + } else { + if(!routeId) { + // go to add conditions to the route + res.redirect(`${routeQuestion}/question-to-skip-to`) + } else { + // if we are editing an existing ‘route for any other answer’ we need to update the routeQuestion + res.redirect(`../${routeQuestion}/question-to-skip-to`) + } + } +} +router.post('/form-designer/question-routes/:pageId(\\d+)/other-answer-route-start', postRouteOtherAnswerStart) +router.post('/form-designer/question-routes/:pageId(\\d+)/:routeQuestion(\\d+)/other-answer-route-start', postRouteOtherAnswerStart) + +// Render ‘Route for any other answer’ end page question +router.get('/form-designer/question-routes/:pageId(\\d+)/:routeQuestion(\\d+)/question-to-skip-to', function (req, res) { + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + var routeQuestion = parseInt(req.params.routeQuestion, 10) + var routeIndex = routeQuestion + return res.render('form-designer/question-routes/question-to-skip-to', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData, + routeIndex: routeIndex + }) +}) + +// Finish creating ‘Route for any other answer’ - button journey +router.post('/form-designer/question-routes/:pageId(\\d+)/:routeQuestion(\\d+)/secondary-skip-end', function (req, res) { + const errors = {} + var { routeEnd, pages } = req.session.data + var routeQuestion = parseInt(req.params.routeQuestion, 10) + var pageId = parseInt(req.params.pageId, 10) + + // If the no question to start the route has been selected, create an error to be displayed to the user + if (!routeEnd?.length) { + errors.routeEnd = { + text: 'Select the question you want to skip the person to', + href: "#routeEnd" + } + } else { + /* + now add the routing to the correct question + for page in req.session.data.pages + if page.pageIndex == routeQuestion + page.routing = { 'skipTo': routeEnd } + + clear routeQuestion and routeEnd just before we redirect + */ + for (let index = 0; index < pages.length; index++) { + const element = pages[index]; + // add routing value with end point to the relevant question + if ((parseInt(element.pageIndex, 10)) == routeQuestion) { + element.routing = { 'baseQuestion': pageId, 'noAnswer': true, 'thenSkipTo': routeEnd } + } + // we also need to add a value to the routing value of the original question + if ((parseInt(element.pageIndex, 10)) == pageId) { + element.routing.secondary = 'true' + element.routing.secondaryQuestion = routeQuestion + } + } + } + + // 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(containsErrors) { + res.render('form-designer/question-routes/question-to-skip-to', { errors, errorList, containsErrors, pageId, routeQuestion }) + } else { + // reset our temporary route session data + req.session.data.routeQuestion = undefined + req.session.data.routeEnd = undefined + // set a success message to declare that ‘route for any other answer’ has been saved + req.session.data.successMessage = "Route for any other answer has been saved" + // go to back to question routes summary screen + res.redirect(`../routes-summary`) + } +}) + + +/* Delete route journeys */ + +// Render are you sure you want to delete ‘Route 1’ or all routes +router.get('/form-designer/question-routes/:pageId(\\d+)/are-you-sure', 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/question-routes/are-you-sure', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData + }) +}) + +// Check if we should delete ‘Route 1’ - button journey +router.post('/form-designer/question-routes/:pageId(\\d+)/are-you-sure', function (req, res) { + const errors = {} + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + var { deleteRoute, pages, action } = req.session.data + + // If the ‘skip the person’ to input has not been selected, create an error to be displayed to the user + if (!deleteRoute?.length) { + if (action?.length && (action === 'deleteRoute1')) { + errors.deleteRoute = { + text: 'Select ‘Yes’ if you want to delete route 1', + href: "#deleteRoute" + } + } else { + errors.deleteRoute = { + text: 'Select ‘Yes’ to delete this question’s routes', + href: "#deleteRoute" + } + } + } + + // reset action + req.session.data.action = 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(containsErrors) { + res.render('form-designer/question-routes/are-you-sure', { errors, errorList, containsErrors, pageId, pageIndex, pageData }) + } else if (deleteRoute?.length && (deleteRoute === 'Yes')) { + /* + go through all of the forms questions + for page in data.pages + check if question has a secondary route + if pageData.routing.secondary + get the secondary route start question + delete ‘route 1’ + we now need to find the secondary route start question + for page in data.pages + if secondary route start question + delete ‘route for any other answer’ + now we can take the user back to their list of questions + */ + for (let index = 0; index < pages.length; index++) { + const element = pages[index]; + var secondaryQuestion = '' + + // get current question + if ((parseInt(element.pageIndex, 10)) == pageIndex) { + // check if question has a secondary route + if (element.routing.secondary) { + // temporarily store the skipTo question in a variable + secondaryQuestion = element.routing.secondaryQuestion + } + // delete the routing + element.routing = undefined + } + + // if there is a secondary route we need to delete this too + if (typeof secondaryQuestion !== 'undefined') { + // re-loop through forms questions to find the ‘route for any other answer’ start question + for (let secondaryIndex = 0; secondaryIndex < pages.length; secondaryIndex++) { + const element = pages[secondaryIndex]; + // get secondaryQuestion + if ((parseInt(element.pageIndex, 10)) == secondaryQuestion) { + // delete the routing + element.routing = undefined + } + } + } + } + // reset temporary page answer + req.session.data.deleteRoute = undefined + // set a success message to declare that routes have been deleted + req.session.data.successMessage = "Question " + (pageIndex + 1) + "’s routes have been deleted" + // go to question X’s routes summary screen + res.redirect(`../../your-questions`) + } else { + // reset temporary page answer + req.session.data.deleteRoute = undefined + // if we are not deleting the route take the person back to the question routes summary + res.redirect(`routes-summary`) + } +}) + +// Render are you sure you want to delete ‘Route 1’ +router.get('/form-designer/question-routes/:pageId(\\d+)/delete-secondary-route', 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/question-routes/delete-secondary-route', { + pageId: pageId, + pageIndex: pageIndex, + pageData: pageData + }) +}) + +// Check if we should delete ‘Route for any other answer’ - button journey +router.post('/form-designer/question-routes/:pageId(\\d+)/delete-secondary-route', function (req, res) { + const errors = {} + var pageId = parseInt(req.params.pageId, 10) + var pageIndex = pageId + var pageData = req.session.data.pages[pageIndex] + var { deleteRouteOtherAnswer, pages } = req.session.data + + // If the ‘skip the person’ to input has not been selected, create an error to be displayed to the user + if (!deleteRouteOtherAnswer?.length) { + errors.deleteRouteOtherAnswer = { + text: 'Select if you want to delete route for any other answer', + href: "#deleteRouteOtherAnswer" + } + } + + // 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(containsErrors) { + res.render('form-designer/question-routes/delete-secondary-route', { errors, errorList, containsErrors, pageId, pageIndex, pageData }) + } else if (deleteRouteOtherAnswer?.length && (deleteRouteOtherAnswer === 'Yes')) { + // reset temporary page answer + req.session.data.deleteRouteOtherAnswer = undefined + /* + go through all of the forms questions + for page in data.pages + find this question with route + if page.routing.baseQuestion == pageIndex + delete ‘route for any other answer’ + now we can take the user back to their list of questions + */ + for (let index = 0; index < pages.length; index++) { + const element = pages[index]; + var baseQuestion = '' + + // get current question + if (element.routing && ((parseInt(element.routing.baseQuestion, 10)) == pageIndex)) { + // temporarily store the baseQuestion question in a variable + baseQuestion = element.routing.baseQuestion + // delete the routing + element.routing = undefined + } + + // now find the ‘route 1’ start question + for (let primaryIndex = 0; primaryIndex < pages.length; primaryIndex++) { + const page = pages[primaryIndex]; + // get skipToQuestion + if (page.routing && ((parseInt(page.pageIndex, 10)) == (parseInt(baseQuestion, 10)))) { + // delete the routing + page.routing.secondary = undefined + page.routing.secondaryQuestion = undefined + } + } + } + // set a success message to declare that ‘route for any other answer’ has been deleted + req.session.data.successMessage = "Route for any other answer has been deleted" + // go to question X’s routes summary screen + res.redirect(`routes-summary`) + } else { + // reset temporary page answer + req.session.data.deleteRouteOtherAnswer = undefined + // if we are not deleting the route take the person back to the question routes summary + res.redirect(`routes-summary`) + } +}) + +module.exports = router \ No newline at end of file diff --git a/app/views/form-designer/question-routes/are-you-sure.html b/app/views/form-designer/question-routes/are-you-sure.html new file mode 100644 index 00000000..6b008e8e --- /dev/null +++ b/app/views/form-designer/question-routes/are-you-sure.html @@ -0,0 +1,69 @@ +{% extends "layout-govuk-forms.html" %} + +{% if data.action == 'deleteRoute1' %} +{% set pageTitle = 'Are you sure you want to delete route 1?' %} +{% else %} +{% set pageTitle = 'Are you sure you want to delete all question ' + ((pageIndex + 1) or 'X') + '’s routes?' %} +{% endif %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{pageTitle}} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + Back question {{ ((pageIndex + 1) or 'X') }}’s routes +{% endblock %} + +{% block content %} +
+
+ + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {% if pageData.routing.secondary and data.action == 'deleteRoute1' %} + {# only show the ‘important’ notification banner if the form creator is trying to delete ‘route 1’ #} + {{ govukNotificationBanner({ + text: "If you delete this route, the route for any other answer will also be deleted" + }) }} + {% endif %} + + + {{ 'Question ' + ((pageIndex + 1) or 'X') + '’s routes' }} + + {{ govukRadios({ + name: "deleteRoute", + fieldset: { + legend: { + text: pageTitle, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + } + }, + items: [ + { + value: "Yes", + text: "Yes" + }, + { + value: "No", + text: "No" + } + ], + errorMessage: { text: errors['deleteRoute'].text } if errors['deleteRoute'].text + }) }} + + {{ govukButton({ + text: "Save and continue" + }) }} + +
+
+ + +{% endblock %} diff --git a/app/views/form-designer/question-routes/conditions.html b/app/views/form-designer/question-routes/conditions.html new file mode 100644 index 00000000..b1e33e7f --- /dev/null +++ b/app/views/form-designer/question-routes/conditions.html @@ -0,0 +1,157 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageTitle = 'Add route 1' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{pageTitle}}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + + Back + +{% endblock %} + +{% block content %} +
+
+
+ + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + + {{ 'Question ' + ((pageIndex + 1) or 'X') + '’s routes' }} + +

{{ pageTitle }}

+ + {{ govukSummaryList({ + rows: [ + { + key: { + text: "Question " + ((pageIndex + 1) or 'X') + }, + value: { + text: pageData['long-title'] or 'Not answered' + }, + actions: { + items: [ + { + href: "new-condition", + text: "Change", + visuallyHiddenText: " question" + } + ] + } if not ((pageData) and (pageData.routing.skipTo) and (pageData.routing.answer)) + } + ] + }) }} + + {# need to get an idea of which page we are trying to skip to so we will hold it in a temporary variable to use for checking if an item in the ‘select’ list has been chosen #} + {% set temp = '' %} + {% for page in data.pages -%} + {% if (page.routing.skipTo) %} + {% set temp = page.routing.skipTo %} + {% endif %} + {% endfor %} + + {# create a new temporary list to use in our ‘select’ component, also add the default ‘select a/an...’ #} + {% set tempAnswers = [{ + value: '', + text: 'Select an answer' + }] %} + {% set tempQuestions = [{ + value: '', + text: 'Select a question or page' + }] %} + + {% for page in data.pages -%} + + {# if this object is the current page #} + {% if (page.pageIndex|int) == (pageIndex) %} + {# add the list of possible answers to the route question to our temporary answers list #} + {% for item in page['item-list'] %} + {% set tempAnswers = ( + tempAnswers.push({ + value: item, + text: item + }), tempAnswers) + %} + {% endfor %} + {% endif %} + + {# if this object is is after the route question #} + {% if (page.pageIndex|int) > (pageIndex + 1) %} + {# add all the questions after the route question to our temporary questions list #} + {% set tempQuestions = ( + tempQuestions.push({ + value: page.pageIndex, + text: (page.pageIndex|int + 1) + '. ' + page['long-title'] + }), tempQuestions) + %} + {# we also need to add the CYA page to the list of options #} + {% if loop.last %} + {% set tempQuestions = ( + tempQuestions.push({ + value: 'cya', + text: data.checkAnswersTitle + }), tempQuestions) + %} + {% endif %} + {% endif %} + {%- endfor %} + + {{ govukSelect({ + id: "route-1-answer", + name: "route1Answer", + label: { + text: "is answered as", + classes: 'govuk-label--s' + }, + value: pageData.routing.answer or data['route1Answer'], + items: tempAnswers, + errorMessage: { text: errors['route1Answer'].text } if errors['route1Answer'].text + }) }} + + {{ govukSelect({ + id: "route-1-end", + name: "route1End", + label: { + text: "skip the person to", + classes: 'govuk-label--s' + }, + items: tempQuestions, + value: pageData.routing.skipTo or data['route1End'], + errorMessage: { text: errors['route1End'].text } if errors['route1End'].text + }) }} + +
+ {{ govukButton({ + text: "Save and continue" + }) }} +
+ + {% if (pageData) and (pageData.routing.skipTo) and (pageData.routing.answer) %} + {{ govukButton({ + text: "Delete route", + classes: "govuk-button--warning", + name: "action", + value: "deleteRoute1" + }) }} + {% endif %} + +
+
+
+{% endblock %} + +{% block pageScripts %} + +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/question-routes/delete-secondary-route.html b/app/views/form-designer/question-routes/delete-secondary-route.html new file mode 100644 index 00000000..9ef93266 --- /dev/null +++ b/app/views/form-designer/question-routes/delete-secondary-route.html @@ -0,0 +1,58 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageTitle = 'Are you sure you want to delete the route for any other answer?' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{pageTitle}} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + Back question {{ ((pageIndex + 1) or 'X') }}’s routes +{% endblock %} + +{% block content %} +
+
+
+ + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + + {{ 'Question ' + ((pageIndex + 1) or 'X') + '’s routes' }} + + {{ govukRadios({ + name: "deleteRouteOtherAnswer", + fieldset: { + legend: { + text: pageTitle, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + } + }, + items: [ + { + value: "Yes", + text: "Yes" + }, + { + value: "No", + text: "No" + } + ], + errorMessage: { text: errors['deleteRouteOtherAnswer'].text } if errors['deleteRouteOtherAnswer'].text + }) }} + + {{ govukButton({ + text: "Save and continue" + }) }} +
+
+
+ + +{% endblock %} diff --git a/app/views/form-designer/question-routes/new-condition.html b/app/views/form-designer/question-routes/new-condition.html index b5ac3ef8..0245a9a7 100644 --- a/app/views/form-designer/question-routes/new-condition.html +++ b/app/views/form-designer/question-routes/new-condition.html @@ -1,6 +1,8 @@ {% extends "layout-govuk-forms.html" %} -{% set pageTitle = 'Add a question route' %} +{% set pageTitle = 'Add a route from a question' %} +{% set pageQuestion = 'Which question do you want to add a route from?' %} +{% set pageHint = 'A route can only start from a question where people select one item from a list. You can only add one route from each question.' %} {% block pageTitle %} {{ "Error: " if containsErrors }}{{pageTitle}}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms @@ -34,9 +36,45 @@

{{ pageTitle }}

- You can send people directly to the question or page you want, based on their previous answer. This means they’ll only see questions that are relevant to them. + You can set up a route so if someone selects a specific answer to a question they’ll skip forward to a later question, or the end of the form.

+ {% if data.pages.length >= 2 %} + + {% set tempQuestions = [] %} + {% for page in data.pages -%} + {% if page['type'] == 'select' and page['listSettings'].includes('oneOption') and not loop.last %} + {% set tempQuestions = ( + tempQuestions.push({ + value: page.pageIndex, + text: (page.pageIndex|int + 1) + '. ' + page['long-title'], + checked: true if data.routeStartQuestion == (page.pageIndex|int + 1) + }), tempQuestions) + %} + {% endif %} + {%- endfor %} + + {{ govukRadios({ + name: "routeStartQuestion", + fieldset: { + legend: { + text: pageQuestion, + classes: "govuk-fieldset__legend--m" + } + }, + hint: { + text: pageHint + }, + items: tempQuestions, + errorMessage: { text: errors['routeStartQuestion'].text } if errors['routeStartQuestion'].text + }) }} + + {{ govukButton({ + text: "Continue" + }) }} + + {% else %} +

What you need to create a route

Before you can add a route you’ll need: @@ -49,8 +87,10 @@

What you need to create a route

You can only add one route from each question.

+ {% endif %} +

- Go to your questions + Back to your questions

diff --git a/app/views/form-designer/question-routes/other-answer-route.html b/app/views/form-designer/question-routes/other-answer-route.html new file mode 100644 index 00000000..47f28153 --- /dev/null +++ b/app/views/form-designer/question-routes/other-answer-route.html @@ -0,0 +1,85 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageTitle = 'Which question do you want to add a route from?' %} +{% set pageHint = 'The person will be skipped forward after they’ve answered this question' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{pageTitle}}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + {% if previousPage and ('your-questions' in previousPage) %} + + Back to your questions + + {% else %} + + Back + + {% endif %} +{% endblock %} + +{% block content %} +
+
+
+ + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + + {{ 'Question ' + ((pageIndex + 1) or 'X') + '’s routes: for any other answer' }} + + + {% set tempQuestions = [] %} + {% for page in data.pages -%} + {% if (page.pageIndex > (pageIndex|int)) and not loop.last %} + {% set tempQuestions = ( + tempQuestions.push({ + value: page.pageIndex, + text: (page.pageIndex|int + 1) + '. ' + page['long-title'], + checked: true if ('routing' in page) + }), tempQuestions) + %} + {% endif %} + {%- endfor %} + + {{ govukRadios({ + name: "routeQuestion", + fieldset: { + legend: { + text: pageTitle, + isPageHeading: true, + classes: "govuk-fieldset__legend--l" + } + }, + hint: { + text: pageHint + }, + items: tempQuestions, + errorMessage: { text: errors['routeQuestion'].text } if errors['routeQuestion'].text + }) }} + + {{ govukButton({ + text: "Continue" + }) }} + +

+ Cancel +

+ +
+
+
+{% endblock %} + +{% block pageScripts %} + +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/question-routes/question-to-skip-to.html b/app/views/form-designer/question-routes/question-to-skip-to.html new file mode 100644 index 00000000..865d4d9a --- /dev/null +++ b/app/views/form-designer/question-routes/question-to-skip-to.html @@ -0,0 +1,117 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageTitle = 'Set question or page to skip to' %} +{% set pageQuestion = 'Which question or page do you want to skip to?' %} +{% set pageHint = 'This is the next question or page that people who select any other answer will see after question ' + (routeIndex + 1) + '.' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{pageTitle}}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + + Back + +{% endblock %} + +{% block content %} +
+
+
+ + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + + {{ 'Question ' + ((pageIndex + 1) or 'X') + '’s routes: for any other answer' }} + +

{{ pageTitle }}

+ + {% set routeStart = '' %} + {% for page in data.pages -%} + {% if (page.pageIndex|int) == (routeIndex) %} + {% set routeStart = page['long-title'] %} + {% endif %} + {%- endfor %} + + {{ govukSummaryList({ + rows: [ + { + key: { + text: "Question " + ((routeIndex + 1) or 'X') + }, + value: { + text: routeStart or 'Not answered' + } + } + ] + }) }} + + {# need to get an idea of which page we are trying to skip to so we will hold it in a temporary variable to use for checking if an item in the ‘select’ list has been chosen #} + {% set temp = '' %} + {% for page in data.pages -%} + {% if (page.routing.thenSkipTo) %} + {% set temp = page.routing.thenSkipTo %} + {% endif %} + {% endfor %} + + {% set tempQuestions = [] %} + {% for page in data.pages -%} + {% if (page.pageIndex > (routeIndex + 1)) %} + {% set tempQuestions = ( + tempQuestions.push({ + value: page.pageIndex, + text: (page.pageIndex|int + 1) + '. ' + page['long-title'], + checked: true if (temp == page.pageIndex) + }), tempQuestions) + %} + {% endif %} + {% if loop.last %} + {% set tempQuestions = ( + tempQuestions.push({ + value: 'cya', + text: data.checkAnswersTitle, + checked: true if (temp == 'cya') + }), tempQuestions) + %} + {% endif %} + {%- endfor %} + + {{ govukRadios({ + name: "routeEnd", + fieldset: { + legend: { + text: pageQuestion, + classes: "govuk-fieldset__legend--m" + } + }, + hint: { + text: pageHint + }, + items: tempQuestions, + errorMessage: { text: errors['routeEnd'].text } if errors['routeEnd'].text + }) }} + + {{ govukButton({ + text: "Save and continue" + }) }} + +

+ Go to your questions +

+ +
+
+
+{% endblock %} + +{% block pageScripts %} + +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/question-routes/routes-summary.html b/app/views/form-designer/question-routes/routes-summary.html new file mode 100644 index 00000000..e0c0ad12 --- /dev/null +++ b/app/views/form-designer/question-routes/routes-summary.html @@ -0,0 +1,260 @@ +{% extends "layout-govuk-forms.html" %} + +{% set pageTitle = 'Question ' + ((pageIndex + 1) or 'X') + '’s routes' %} + +{% block pageTitle %} + {{ "Error: " if containsErrors }}{{ pageTitle }}: {{ data.formTitle or '[formTitle]' }} - GOV.UK Forms +{% endblock %} + +{% block beforeContent %} + + Back + +{% endblock %} + +{% block content %} +
+
+
+ + {% if successMessage %} + {{ govukNotificationBanner({ + type: 'success', + text: successMessage + }) }} + {% endif %} + + {% if containsErrors %} + {{ govukErrorSummary({ + titleText: "There is a problem", + errorList: errorList + }) }} + {% endif %} + + {{ data.formTitle or '[formTitle]' }} +

{{ pageTitle }}

+ + {% set routeEnd = '' %} + {% set routeEndText = '' %} + {% set countQs = 0 %} + {# loop to get ‘Route 1’ skip to question text to display in the summary card #} + {% for page in data.pages -%} + + {# quick way for us to get if there are enough questions left that a for any other answer route would work or should be offered #} + {% if (page.pageIndex|int+1) > (pageIndex|int+1) %} + {% set countQs = countQs + 1 %} + {% endif %} + + {# set the skip to question content to an existing question from the form #} + {% if (page.pageIndex|int + 1) == (pageData.routing.skipTo|int + 1) %} + {% set routeEndText = (page.pageIndex|int + 1) + '. ' + page['long-title'] %} + {% set routeEnd = (page.pageIndex|int + 1) %} + {# set the skip to content to be check your answers default title #} + {% elif pageData.routing.skipTo === 'cya' %} + {% set routeEndText = data.checkAnswersTitle %} + {% set routeEnd = 'cya' %} + {% endif %} + {%- endfor %} + + {# show the question the routes are associated with #} + {{ govukSummaryList({ + rows: [ + { + key: { + text: "Question " + ((pageIndex + 1) or 'X') + }, + value: { + text: pageData['long-title'] or 'Not answered' + } + } + ] + }) }} + + {# show the ‘Route 1’ summary card #} + {{ govukSummaryList({ + card: { + title: { + text: "Route 1" + }, + actions: { + items: [ + { + href: "./conditions", + text: "Edit", + visuallyHiddenText: " route 1" + } + ] + } + }, + rows: [ + { + key: { + text: "If answered as" + }, + value: { + text: pageData.routing.answer or 'Not answered' + } + }, + { + key: { + text: "skip the person to" + }, + value: { + text: routeEndText or 'Not answered' + } + } + ] + }) }} + + {# show ‘Route for any other answer’ summary card if one has been added #} + {% if pageData.routing.secondary === 'true' %} + + {# we need a way to get the question that we want to suggest to start the for any other answer route from #} + {% set continueTo = '' %} + {% set thenAfter = '0' %} + {% set thenAfterText = '' %} + {% set skipPersonTo = '' %} + {% for page in data.pages %} + {% if page.pageIndex == (pageData.pageIndex|int + 1) %} + {% set continueTo = (page.pageIndex|int + 1) + '. ' + page['long-title'] %} + {% endif %} + {# find the secondary route in the questions list #} + {% if page.routing and (page.routing.baseQuestion == (pageData.pageIndex)) %} + {% set thenAfter = page.pageIndex|int %} + {% set thenAfterText = (page.pageIndex|int + 1) + '. ' + page['long-title'] %} + {% if page.routing.thenSkipTo == 'cya' %} + {% set skipPersonTo = data.checkAnswersTitle %} + {% else %} + {% for otherRoutePage in data.pages %} + {% if (otherRoutePage.pageIndex|int) == (page.routing.thenSkipTo|int) %} + {% set skipPersonTo -%} + {{ otherRoutePage.pageIndex|int + 1 }}. “{{ otherRoutePage['long-title'] }}” + {%- endset %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} + {% endfor %} + + {{ govukSummaryList({ + card: { + title: { + text: "Route for any other answer" + }, + actions: { + items: [ + { + href: "delete-secondary-route", + text: "Delete", + visuallyHiddenText: " route for any other answer" + } + ] + } + }, + rows: [ + { + key: { + text: "Continue to" + }, + value: { + text: continueTo or 'Next question' + } + }, + { + key: { + text: "Then after" + }, + value: { + text: thenAfterText or 'Not answered' + }, + actions: { + items: [ + { + href: thenAfter + "/other-answer-route", + text: "Change", + visuallyHiddenText: " question to skip from" + } + ] + } + }, + { + key: { + text: "skip the person to" + }, + value: { + text: skipPersonTo or 'Not answered' + }, + actions: { + items: [ + { + href: thenAfter + "/question-to-skip-to", + text: "Change", + visuallyHiddenText: " skip the person to" + } + ] + } + } + ] + }) }} + + {{ govukButton({ + text: "Delete all routes", + classes: "govuk-button--warning", + name: "action", + value: "deleteAllRoutes" + }) }} + + {% else %} + + {# we need a way to get the question that we want to suggest to start the for any other answer route from #} + {% set suggestedQuestion = '' %} + {% set suggestedQuestionText = '' %} + {% for page in data.pages %} + {% if (routeEnd != 'cya') or (countQs >= 2) %} + {% if page.pageIndex == pageData.routing.skipTo|int - 1 %} + {% set suggestedQuestion = (page.pageIndex|int + 1) %} + {% set suggestedQuestionText = (page.pageIndex|int + 1) + ', ‘' + page['long-title'] + '’' %} + {% endif %} + {% endif %} + {% endfor %} + +

If people select any other answer

+

+ People who select any other answer will continue to question {{ (pageIndex + 2) or 'Y' }} and through the rest of the form. +

+ {% if routeEnd != 'cya' %} +

+ You can change this by adding a route from {{ suggestedQuestionText or 'Z, ‘Example question’' }}. +

+ + {# if not the last question, and the previous question isn’t the last question #} + + + + {{ govukButton({ + text: "Add a route from question " + (suggestedQuestion|int or 'Z'), + classes: "govuk-button--secondary" + }) }} + +

+ Add a route from a different question +

+ {% endif %} + + {% endif %} + +

+ Back to your questions +

+ +
+
+
+{% endblock %} + +{% block pageScripts %} + +{% endblock %} \ No newline at end of file diff --git a/app/views/form-designer/signon/dashboard.html b/app/views/form-designer/signon/dashboard.html index 085cd8a2..41f24010 100644 --- a/app/views/form-designer/signon/dashboard.html +++ b/app/views/form-designer/signon/dashboard.html @@ -61,7 +61,7 @@
  • - Firstname Lastname + {{ data.defaultUser }}
  • diff --git a/app/views/form-designer/your-form.html b/app/views/form-designer/your-form.html index c4599de4..b020f136 100644 --- a/app/views/form-designer/your-form.html +++ b/app/views/form-designer/your-form.html @@ -12,7 +12,7 @@ {% elif data['journey'] and data['journey'] == 'orgAdminTasks' %} Back to your group {% else %} - Back to your forms + Back to {{ data.defaultGroup or 'your forms' }} {% endif %} {% endblock %} diff --git a/app/views/form-designer/your-forms.html b/app/views/form-designer/your-forms.html index 29521289..ca5342bc 100644 --- a/app/views/form-designer/your-forms.html +++ b/app/views/form-designer/your-forms.html @@ -1,15 +1,23 @@ {% extends "layout-govuk-forms.html" %} -{% set pageTitle = 'Home' %} +{% set pageTitle = data.defaultGroup %} {% block pageTitle %} - {{pageTitle}} - {{serviceName}} + {{ pageTitle }} - {{ serviceName }} {% endblock %} {% block content %}
    -

    {{serviceName}}

    + Active group +

    {{ pageTitle }}

    + +

    + Change the name of this group +

    +

    + Edit members of this group +

    {{ govukButton({ text: "Create a form", @@ -19,10 +27,11 @@

    {{serviceName}}

    {% if data['formTitle'] %} - + + @@ -31,6 +40,9 @@

    {{serviceName}}

    + diff --git a/app/views/product-pages/group-admin/grouplanding.html b/app/views/product-pages/group-admin/grouplanding.html index d4182908..d6f321d7 100644 --- a/app/views/product-pages/group-admin/grouplanding.html +++ b/app/views/product-pages/group-admin/grouplanding.html @@ -64,7 +64,7 @@

    {{ data['groupName'] or 'Your test forms' }}

    {{data['formTitle']}}
    [departmentName] formsForms in ‘{{ pageTitle }}’
    Form nameCreated by Status
    {{data['formTitle']}} + {{ data.defaultUser }} + {% if data['status'] %} {{govukTag({ diff --git a/app/views/form-designer/your-questions.html b/app/views/form-designer/your-questions.html index 4792bfe4..a2b1b560 100644 --- a/app/views/form-designer/your-questions.html +++ b/app/views/form-designer/your-questions.html @@ -82,8 +82,8 @@

    {{loop.index}} @@ -122,6 +122,60 @@

    +
    + Question {{ page["pageIndex"] | int + 1 }}’s routes +
    +
    + If “{{ page['long-title'] }}” is answered as “{{ page.routing.answer }}” go to {{ skipPage }} +
    +
    + + Edit question {{ page["pageIndex"] | int + 1 }}’s routes + +
    + + {% endif %} + {# finally we need to add routing not based on an answer if there is any #} + {% if page.routing.noAnswer %} + {% set skipPage = '' %} + {% if page.routing.thenSkipTo == 'cya' %} + {% set skipPage = '“' + data.checkAnswersTitle + '”' %} + {% else %} + {% for otherRoutePage in data.pages %} + {% if (otherRoutePage.pageIndex|int) == (page.routing.thenSkipTo|int) %} + {% set skipPage -%} + {{ otherRoutePage.pageIndex|int + 1 }}, “{{ otherRoutePage['long-title'] }}” + {%- endset %} + {% endif %} + {% endfor %} + {% endif %} +
    +
    + Question {{ page.routing.baseQuestion | int + 1 }}’s routes +
    +
    + After {{ page.pageIndex|int + 1 }}, “{{ page['long-title'] }}” go to {{ skipPage }} +
    +
    + + Edit question {{ page.routing.baseQuestion | int + 1 }}’s routes + +
    +
    + {% endif %} {%- endfor %} diff --git a/app/views/layout-govuk-forms.html b/app/views/layout-govuk-forms.html index f32d9fd6..0037a05c 100644 --- a/app/views/layout-govuk-forms.html +++ b/app/views/layout-govuk-forms.html @@ -9,7 +9,7 @@ navigationClasses: "govuk-header__navigation--end", navigation: [ { - text: "Firstname Lastname" + text: data.defaultUser }, { href: "/form-designer/signon/sign-in", diff --git a/app/views/product-pages/group-admin/group.html b/app/views/product-pages/group-admin/group.html index 3945adc1..037ad0ba 100644 --- a/app/views/product-pages/group-admin/group.html +++ b/app/views/product-pages/group-admin/group.html @@ -75,7 +75,7 @@

    Trial groups

    - {{ data.createdBy or 'Firstname Lastname' }} + {{ data.createdBy or data.defaultUser }}
    - Firstname Lastname + {{ data.defaultUser }} {% if data['status'] %} diff --git a/app/views/product-pages/group-admin/grouplanding2.html b/app/views/product-pages/group-admin/grouplanding2.html index de8e2e40..d92eeb61 100644 --- a/app/views/product-pages/group-admin/grouplanding2.html +++ b/app/views/product-pages/group-admin/grouplanding2.html @@ -61,7 +61,7 @@

    {{ data['groupName'] or 'Your test forms' }}

    {{data['formTitle']}}
    - Firstname Lastname + {{ data.defaultUser }} {% if data['status'] %} diff --git a/app/views/product-pages/group-admin/tasklist-activegroup.html b/app/views/product-pages/group-admin/tasklist-activegroup.html index 52ea31af..1836e634 100644 --- a/app/views/product-pages/group-admin/tasklist-activegroup.html +++ b/app/views/product-pages/group-admin/tasklist-activegroup.html @@ -3,604 +3,434 @@ - Create a form: [formTitle] - GOV.UK Forms - + Create a form: [formTitle] - GOV.UK Forms + - - - - - - - - - - - - + + + + + + + + + + + < script > document.body.className += ' js-enabled' + ( + 'noModule' in HTMLScriptElement.prototype + ? ' govuk-frontend-supported' + : ''); + + + Skip to main content + + - +
    - - - - - - - - - Skip to main content - - - - - +
    +
    +
    - -
    - - Back to your group + [formTitle] +

    Create a form

    +
    +
    Status
    +
    + + Draft + -
    - -
    -
    +
    +
    - +

    + You have completed 0 of 9 tasks. +

    - - [formTitle] -

    Create a form

    +

    + 1. Create your form +

    -
    -
    Status
    -
    - - Draft - +
      -
    -
    + + + + + +

    + + Optional tasks +

    - - + + +

    + 2. + + Set email address for completed forms +

    +
    +
    + + Status + Cannot start yet +
    + + - - +

    + 3. + + Provide privacy and contact details +

    + +

    + 4. + + Make your form live +

    + +
    + - - - +
    +
    +
    +
    +
    -

    - 4. Make your form live -

    + - - - + - - - + - - - + - - - + - - - + - - - + - - - + + + + /* Copy the text from the node */ + navigator + .clipboard + .writeText(range); + } - + // call function from `assets/javascripts/application.js` + // removeSuccessNotification(); + - + \ No newline at end of file diff --git a/app/views/product-pages/group-admin/tasklist-trialgroup.html b/app/views/product-pages/group-admin/tasklist-trialgroup.html index 7f3da4cf..a73d4393 100644 --- a/app/views/product-pages/group-admin/tasklist-trialgroup.html +++ b/app/views/product-pages/group-admin/tasklist-trialgroup.html @@ -1,320 +1,231 @@ - - - - Create a form: [formTitle] - GOV.UK Forms - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Skip to main content - - - - - - - - - -
    - - Back to your group - - -
    - -
    -
    - - - - - [formTitle] -

    Create a form

    - -
    -
    Status
    -
    - - Draft - - -
    -
    - - - -

    - You have completed 0 of 9 tasks. -

    - -

    - 1. Create your form -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Not yet started + +
    + + + + Not yet started + +
    + + +

    + + Optional tasks +

    + +

    - 2. Set email address for completed forms + 2. + + Set email address for completed forms

    - -
    - Status + + Status Cannot start yet
    - - - - - - - - - - - - - - - - - -

    - 3. Provide privacy and contact details + 3. + + Provide privacy and contact details

    - - - - - - - - - - - - -

    - 4. Make your form live + 4. + + Make your form live

    - - +
    - - - - - - - - - -
    - - - -