From 0b4f34b807d15bd8f76b386940f460ccbf849d3f Mon Sep 17 00:00:00 2001 From: Masuk Kazi Date: Thu, 11 Jul 2024 01:35:19 +0100 Subject: [PATCH 1/5] OOC-4396: updated json --- runner/src/server/forms/ReportAnOutbreak.json | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/runner/src/server/forms/ReportAnOutbreak.json b/runner/src/server/forms/ReportAnOutbreak.json index cb141b045..0b2a2bf08 100644 --- a/runner/src/server/forms/ReportAnOutbreak.json +++ b/runner/src/server/forms/ReportAnOutbreak.json @@ -1571,26 +1571,31 @@ }, { "path": "/feedback-on-the-care-obra-tool", - "title": "Section 10 - Feedback on the Care OBRA Tool", + "title": "Section 10 - Give feedback on Report an outbreak", "components": [ - { - "name": "zTXeZb", - "options": {}, - "type": "Para", - "content": "Please provide your feedback.", - "schema": {} - }, { "name": "S10Q1", "options": { "required": true }, "type": "CheckboxesField", - "title": "S10Q1. How would you describe this risk assessment tool?", + "title": "How would you describe this risk assessment tool?", "nameHasError": false, "list": "icNyDJ", "schema": {}, - "hint": "Please note that you can select more than one option" + "hint": "Select all that apply" + }, + { + "name": "S10Q2", + "options": { + "required": false, + "optionalText": false + }, + "type": "MultilineTextField", + "title": "Tell us about any difficulties or highlights you experienced, and how we could improve the service.", + "nameHasError": false, + "schema": {}, + "hint": "Do not include any personal information here, for example patient or disease details" } ], "next": [ @@ -1861,13 +1866,25 @@ "name": "icNyDJ", "type": "string", "items": [ + { + "text": "Useful resource", + "value": "Useful resource" + }, + { + "text": "Easy to understand", + "value": "Easy to understand" + }, { "text": "Easy to complete", "value": "Easy to complete" }, { - "text": "Useful resource", - "value": "Useful resource" + "text": "Quick to complete", + "value": "Quick to complete" + }, + { + "text": "Some questions were unclear", + "value": "Some questions were unclear" }, { "text": "Not detailed enough", @@ -1877,21 +1894,13 @@ "text": "Too detailed", "value": "Too detailed" }, - { - "text": "Quick to complete", - "value": "Quick to complete" - }, { "text": "Too time consuming", "value": "Too time consuming" }, { - "text": "Easy to understand", - "value": "Easy to understand" - }, - { - "text": "Some questions were unclear", - "value": "Some questions were unclear" + "text": "Other (specify below)", + "value": "Other (specify below)" } ] }, From 323bfa39bc3259af56e1b9d82a9e8474729da413 Mon Sep 17 00:00:00 2001 From: Masuk Kazi Date: Wed, 31 Jul 2024 14:51:43 +0100 Subject: [PATCH 2/5] updated textbox validation --- model/src/components/types.ts | 4 +++ runner/src/server/forms/ReportAnOutbreak.json | 8 ++++-- .../engine/components/CheckboxesField.ts | 6 ++-- .../engine/components/MultilineTextField.ts | 28 ++++++++++++++++++- .../plugins/engine/components/helpers.ts | 11 ++++++++ 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/model/src/components/types.ts b/model/src/components/types.ts index 8357d643e..f661a523e 100644 --- a/model/src/components/types.ts +++ b/model/src/components/types.ts @@ -215,6 +215,10 @@ export interface MultilineTextFieldComponent extends TextFieldBase { customValidationMessage?: string; rows?: number; maxWords?: number; + conditionalTextBox?: { + dependsOnFieldName?: string; + dependsOnFieldValue?: string; + }; }; schema: { max?: number; diff --git a/runner/src/server/forms/ReportAnOutbreak.json b/runner/src/server/forms/ReportAnOutbreak.json index 0b2a2bf08..230fcf1b4 100644 --- a/runner/src/server/forms/ReportAnOutbreak.json +++ b/runner/src/server/forms/ReportAnOutbreak.json @@ -1589,10 +1589,14 @@ "name": "S10Q2", "options": { "required": false, - "optionalText": false + "optionalText": false, + "conditionalTextBox": { + "dependsOnFieldName": "S10Q1", + "dependsOnFieldValue": "Other (specify below)" + } }, "type": "MultilineTextField", - "title": "Tell us about any difficulties or highlights you experienced, and how we could improve the service.", + "title": "Tell us about any difficulties or highlights you experienced, and how we could improve the service", "nameHasError": false, "schema": {}, "hint": "Do not include any personal information here, for example patient or disease details" diff --git a/runner/src/server/plugins/engine/components/CheckboxesField.ts b/runner/src/server/plugins/engine/components/CheckboxesField.ts index 73c3c7ba1..37313b6a2 100644 --- a/runner/src/server/plugins/engine/components/CheckboxesField.ts +++ b/runner/src/server/plugins/engine/components/CheckboxesField.ts @@ -13,7 +13,6 @@ export class CheckboxesField extends SelectionControlField { let schema = joi.array().single().label(def.title); if (options.required === false) { - // null or empty string is valid for optional fields schema = schema .empty(null) .items(joi[this.listType]().allow(...this.values, "")); @@ -42,7 +41,10 @@ export class CheckboxesField extends SelectionControlField { getViewModel(formData: FormData, errors: FormSubmissionErrors) { const viewModel = super.getViewModel(formData, errors); - let formDataItems = (formData[this.name] ?? "").split(","); + let formDataItems = (Array.isArray(formData[this.name]) + ? formData[this.name].join(",") + : formData[this.name] ?? "" + ).split(","); viewModel.items = (viewModel.items ?? []).map((item) => ({ ...item, checked: !!formDataItems.find((i) => `${item.value}` === i), diff --git a/runner/src/server/plugins/engine/components/MultilineTextField.ts b/runner/src/server/plugins/engine/components/MultilineTextField.ts index a99640aea..1433b9b1f 100644 --- a/runner/src/server/plugins/engine/components/MultilineTextField.ts +++ b/runner/src/server/plugins/engine/components/MultilineTextField.ts @@ -1,9 +1,10 @@ import { FormComponent } from "./FormComponent"; -import { FormData, FormSubmissionErrors } from "../types"; +import { FormData, FormPayload, FormSubmissionErrors } from "../types"; import Joi, { Schema, StringSchema } from "joi"; import { MultilineTextFieldComponent } from "@xgovformbuilder/model"; import { FormModel } from "server/plugins/engine/models"; import { MultilineTextFieldViewModel } from "server/plugins/engine/components/types"; +import * as helpers from "./helpers"; function inputIsOverWordCount(input, maxWords) { /** @@ -20,6 +21,8 @@ export class MultilineTextField extends FormComponent { schema: MultilineTextFieldComponent["schema"]; customValidationMessage?: string; isCharacterOrWordCount: boolean = false; + dependsOnFieldName; + dependsOnFieldValue; constructor(def: MultilineTextFieldComponent, model: FormModel) { super(def, model); @@ -28,6 +31,10 @@ export class MultilineTextField extends FormComponent { this.schema = schema; let componentSchema = Joi.string().label(def.title).required(); + componentSchema = componentSchema.custom( + helpers.getCustomCheckboxValidator() + ); + if (options.required === false) { componentSchema = componentSchema.allow("").allow(null); } @@ -63,6 +70,11 @@ export class MultilineTextField extends FormComponent { ); } + if (options.conditionalTextBox) { + this.dependsOnFieldName = options.conditionalTextBox.dependsOnFieldName; + this.dependsOnFieldValue = options.conditionalTextBox.dependsOnFieldValue; + } + this.formSchema = componentSchema; } @@ -74,6 +86,20 @@ export class MultilineTextField extends FormComponent { return { [this.name]: this.formSchema as Schema }; } + getStateValueFromValidForm(payload: FormPayload) { + const checkboxSelection = payload[this.dependsOnFieldName]; + const textBoxValue = payload[this.name]; + + if ( + checkboxSelection.includes(this.dependsOnFieldValue) && + textBoxValue === "" + ) { + return "__OTHER_SPECIFY_REQUIRED__"; + } + + return textBoxValue; + } + getViewModel( formData: FormData, errors: FormSubmissionErrors diff --git a/runner/src/server/plugins/engine/components/helpers.ts b/runner/src/server/plugins/engine/components/helpers.ts index d922a1f6e..dbb6ee89a 100644 --- a/runner/src/server/plugins/engine/components/helpers.ts +++ b/runner/src/server/plugins/engine/components/helpers.ts @@ -149,6 +149,17 @@ export function getCustomDateValidator( }; } +export function getCustomCheckboxValidator() { + return (value, helpers: joi.CustomHelpers) => { + if (value === "__OTHER_SPECIFY_REQUIRED__") { + return helpers.error("string.base", { + label: helpers.state.key, + }); + } + return value; + }; +} + export function internationalPhoneValidator( value: string, _helpers: joi.CustomHelpers From 4426d82a65c4586156781d737a87638c1c8e80c4 Mon Sep 17 00:00:00 2001 From: Masuk Kazi Date: Wed, 31 Jul 2024 22:00:21 +0100 Subject: [PATCH 3/5] wip --- .../server/plugins/engine/components/MultilineTextField.ts | 2 +- runner/src/server/plugins/engine/components/helpers.ts | 4 ++-- .../plugins/engine/pageControllers/validationOptions.ts | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/runner/src/server/plugins/engine/components/MultilineTextField.ts b/runner/src/server/plugins/engine/components/MultilineTextField.ts index 1433b9b1f..1d7a4e84d 100644 --- a/runner/src/server/plugins/engine/components/MultilineTextField.ts +++ b/runner/src/server/plugins/engine/components/MultilineTextField.ts @@ -94,7 +94,7 @@ export class MultilineTextField extends FormComponent { checkboxSelection.includes(this.dependsOnFieldValue) && textBoxValue === "" ) { - return "__OTHER_SPECIFY_REQUIRED__"; + return ""; } return textBoxValue; diff --git a/runner/src/server/plugins/engine/components/helpers.ts b/runner/src/server/plugins/engine/components/helpers.ts index dbb6ee89a..5844b4a60 100644 --- a/runner/src/server/plugins/engine/components/helpers.ts +++ b/runner/src/server/plugins/engine/components/helpers.ts @@ -151,8 +151,8 @@ export function getCustomDateValidator( export function getCustomCheckboxValidator() { return (value, helpers: joi.CustomHelpers) => { - if (value === "__OTHER_SPECIFY_REQUIRED__") { - return helpers.error("string.base", { + if (value === "") { + return helpers.error("textbox.conditionalFeedback", { label: helpers.state.key, }); } diff --git a/runner/src/server/plugins/engine/pageControllers/validationOptions.ts b/runner/src/server/plugins/engine/pageControllers/validationOptions.ts index 9fceb9497..df31d101e 100644 --- a/runner/src/server/plugins/engine/pageControllers/validationOptions.ts +++ b/runner/src/server/plugins/engine/pageControllers/validationOptions.ts @@ -29,6 +29,8 @@ const messageTemplate = { dateDayYear: "{{#label}} must include a day and a year", dateDayMonth: "{{#label}} must include a day and a month", dateYear4digits: "The year must include 4 numbers", + conditionalFeedback: + "Give details of any difficulties or highlights you experienced, or how we could improve the service", }; export const messages: ValidationOptions["messages"] = { @@ -63,6 +65,8 @@ export const messages: ValidationOptions["messages"] = { "date.dayYear": messageTemplate.dateDayYear, "date.dayMonth": messageTemplate.dateDayMonth, "date.year4digits": messageTemplate.dateYear4digits, + + "textbox.conditionalFeedback": messageTemplate.conditionalFeedback, }; export const validationOptions: ValidationOptions = { From 55e06d06b039ed89e94d0f02f9e77ec9ef172958 Mon Sep 17 00:00:00 2001 From: Masuk Kazi Date: Thu, 1 Aug 2024 12:17:48 +0100 Subject: [PATCH 4/5] updated validation --- runner/src/server/forms/ReportAnOutbreak.json | 2 +- .../src/server/plugins/engine/components/MultilineTextField.ts | 2 +- runner/src/server/plugins/engine/components/helpers.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/runner/src/server/forms/ReportAnOutbreak.json b/runner/src/server/forms/ReportAnOutbreak.json index 230fcf1b4..e78259bd4 100644 --- a/runner/src/server/forms/ReportAnOutbreak.json +++ b/runner/src/server/forms/ReportAnOutbreak.json @@ -1596,7 +1596,7 @@ } }, "type": "MultilineTextField", - "title": "Tell us about any difficulties or highlights you experienced, and how we could improve the service", + "title": "Tell us about any difficulties or highlights you experienced, and how we could improve the service.", "nameHasError": false, "schema": {}, "hint": "Do not include any personal information here, for example patient or disease details" diff --git a/runner/src/server/plugins/engine/components/MultilineTextField.ts b/runner/src/server/plugins/engine/components/MultilineTextField.ts index 1d7a4e84d..d4c4241a0 100644 --- a/runner/src/server/plugins/engine/components/MultilineTextField.ts +++ b/runner/src/server/plugins/engine/components/MultilineTextField.ts @@ -94,7 +94,7 @@ export class MultilineTextField extends FormComponent { checkboxSelection.includes(this.dependsOnFieldValue) && textBoxValue === "" ) { - return ""; + return "empty"; } return textBoxValue; diff --git a/runner/src/server/plugins/engine/components/helpers.ts b/runner/src/server/plugins/engine/components/helpers.ts index 5844b4a60..b457c84e9 100644 --- a/runner/src/server/plugins/engine/components/helpers.ts +++ b/runner/src/server/plugins/engine/components/helpers.ts @@ -151,7 +151,7 @@ export function getCustomDateValidator( export function getCustomCheckboxValidator() { return (value, helpers: joi.CustomHelpers) => { - if (value === "") { + if (value === "empty") { return helpers.error("textbox.conditionalFeedback", { label: helpers.state.key, }); From e456c2797b3bd5a083b201cf9c994bfee16fd97b Mon Sep 17 00:00:00 2001 From: Masuk Kazi Date: Thu, 1 Aug 2024 12:22:04 +0100 Subject: [PATCH 5/5] formatting --- .../plugins/engine/pageControllers/validationOptions.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runner/src/server/plugins/engine/pageControllers/validationOptions.ts b/runner/src/server/plugins/engine/pageControllers/validationOptions.ts index 35d6022ac..1cdcfccb5 100644 --- a/runner/src/server/plugins/engine/pageControllers/validationOptions.ts +++ b/runner/src/server/plugins/engine/pageControllers/validationOptions.ts @@ -29,7 +29,8 @@ const messageTemplate = { dateDayYear: "{{#label}} must include a day and a year", dateDayMonth: "{{#label}} must include a day and a month", dateYear4digits: "The year must include 4 numbers", - dateChronological: "The date that symptoms started in the {{#compLabel}} must be the same as or after the date that symptoms started in the first case", + dateChronological: + "The date that symptoms started in the {{#compLabel}} must be the same as or after the date that symptoms started in the first case", cqc: "Enter your CQC location ID or select 'My setting is not registered with the CQC'", cqcRegex: "Enter a valid CQC Location ID", @@ -72,8 +73,8 @@ export const messages: ValidationOptions["messages"] = { "date.dayMonth": messageTemplate.dateDayMonth, "date.year4digits": messageTemplate.dateYear4digits, "date.chronological": messageTemplate.dateChronological, - - "textbox.conditionalFeedback": messageTemplate.conditionalFeedback + + "textbox.conditionalFeedback": messageTemplate.conditionalFeedback, }; export const validationOptions: ValidationOptions = {