Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/prototype_v4_1/controllers/question.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { renderQuestion, version, view } = require('../lib/question-renderer')
const { getCheckYourAnswers } = require('../lib/summary')
const {
deleteUnselectedShishaSettingAnswers,
deleteUnselectedSmokingQuantityOtherAnswer,
deleteUnselectedSmokingChangeAnswers,
deleteUnselectedSmokingTypeAnswers,
getFormerSmokerFallbackStep,
Expand Down Expand Up @@ -773,6 +774,7 @@ exports.smokingQuantity_get = (req, res) => {

exports.smokingQuantity_post = (req, res) => {
const { step, steps } = getSmokingTypeStep(req, 'smoking-quantity')
deleteUnselectedSmokingQuantityOtherAnswer(req.session.data.answers, step)
const errors = step ? validateSmokingTypeQuestion(req, 'smoking-quantity', step) : []

if (!step) {
Expand Down Expand Up @@ -859,6 +861,7 @@ exports.smokingQuantityChange_get = (req, res) => {

exports.smokingQuantityChange_post = (req, res) => {
const { step, steps } = getSmokingTypeStep(req, 'smoking-quantity-change')
deleteUnselectedSmokingQuantityOtherAnswer(req.session.data.answers, step, 'quantity')
const errors = step ? validateSmokingTypeQuestion(req, 'smoking-quantity-change', step) : []

if (!step) {
Expand Down
12 changes: 12 additions & 0 deletions app/prototype_v4_1/data/questions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,18 @@ questions:
value: 1_to_2_hours
- label: More than 2 hours
value: more_than_2_hours
- divider: or
- label: Another amount
value: another_amount
conditionalInput:
id: smoking-quantity-other
name: answers[smokingQuantityOther]
answerKey: smokingQuantityOther
label: Enter the number of hours
hint: Give an estimate if you are not sure
suffix: hours
inputmode: numeric
classes: nhsuk-input--width-4
validation:
required: true
validation:
Expand Down
17 changes: 16 additions & 1 deletion app/prototype_v4_1/lib/question-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ const getAnswerValue = (answers = {}, question) => {
return value
}

/**
* Resolve a conditional reveal value from a runtime override or answer key.
*
* @param {Object} answers - Session answers object.
* @param {Object} rule - Conditional validation rule.
* @returns {*} Submitted conditional value.
*/
const getConditionalValue = (answers = {}, rule = {}) => {
if (rule.value !== undefined) {
return rule.value
}

return answers[rule.answerKey]
}

/**
* Resolve a date input value from the answers object.
*
Expand Down Expand Up @@ -128,7 +143,7 @@ const validateConditional = (answers, question, errors) => {
return
}

const conditionalValue = answers[rule.answerKey]
const conditionalValue = getConditionalValue(answers, rule)

if (isBlank(conditionalValue)) {
const error = question.errors?.conditional?.[triggerValue]?.required || {
Expand Down
22 changes: 20 additions & 2 deletions app/prototype_v4_1/lib/summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,24 @@ const formatWeight = (weight = {}) => {
return ''
}

/**
* Format a smoking quantity, including conditional reveal "another amount" answers.
*
* @param {string} type - Tobacco type key.
* @param {Object} answer - Answer object containing quantity fields.
* @param {string} quantityKey - Quantity answer key.
* @returns {string} Formatted quantity answer.
*/
const formatSmokingQuantityAnswer = (type, answer = {}, quantityKey = 'smokingQuantity') => {
if (answer[quantityKey] === 'another_amount') {
return answer.smokingQuantityOther
? formatQuantity(answer.smokingQuantityOther, 'hour', 'hours')
: ''
}

return getSmokingQuantity(type, answer[quantityKey])
}

/**
* Format one or more stored values using display labels.
*
Expand Down Expand Up @@ -226,7 +244,7 @@ const getCheckYourAnswers = (answers = {}) => {
}),
makeSummaryRow({
key: getSmokingStepHeading('smoking-quantity', type, setting, isPast, settingAnswer),
value: getSmokingQuantity(type, settingAnswer.smokingQuantity),
value: formatSmokingQuantityAnswer(type, settingAnswer),
href: getSmokingTypeStepUrl({ page: 'smoking-quantity', type, setting })
})
]
Expand Down Expand Up @@ -270,7 +288,7 @@ const getCheckYourAnswers = (answers = {}) => {
}),
type !== 'shisha' && makeSummaryRow({
key: getSmokingStepHeading('smoking-quantity', type, undefined, isPast, answer),
value: getSmokingQuantity(type, answer.smokingQuantity),
value: formatSmokingQuantityAnswer(type, answer),
href: getSmokingTypeStepUrl({ page: 'smoking-quantity', type })
}),
type !== 'shisha' && makeSummaryRow({
Expand Down
108 changes: 106 additions & 2 deletions app/prototype_v4_1/lib/tobacco-flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,48 @@ const getSmokingChangeAnswer = (answer = {}, change) => {
return answerKey ? answer[answerKey] || {} : {}
}

/**
* Get the object that stores a smoking quantity answer for the current step.
*
* @param {Object} answers - Session answers object.
* @param {SmokingTypeStep} step - Current tobacco step.
* @returns {Object} Answer object containing the quantity answer.
*/
const getSmokingQuantityAnswer = (answers = {}, step = {}) => {
const answer = answers[step.type] || {}

if (step.change) {
return getSmokingChangeAnswer(answer, step.change)
}

if (step.setting) {
return getShishaSettingAnswer(answer, step.setting)
}

return answer
}

/**
* Remove a stale conditional reveal quantity when "another amount" is not selected.
*
* @param {Object} answers - Session answers object, mutated in place.
* @param {SmokingTypeStep} step - Current tobacco step.
* @param {string} quantityKey - Quantity answer key.
*/
const deleteUnselectedSmokingQuantityOtherAnswer = (answers = {}, step, quantityKey = 'smokingQuantity') => {
delete answers.smokingQuantityOther

if (!step) {
return
}

const answer = getSmokingQuantityAnswer(answers, step)

if (answer[quantityKey] !== 'another_amount') {
delete answer.smokingQuantityOther
}
}

/**
* Build contextual comparison text for changed-smoking questions.
*
Expand Down Expand Up @@ -637,6 +679,7 @@ const getSmokingQuantityQuestionOverrides = ({
caption,
name,
value,
conditionalValue,
smokingType
}) => {
const question = getQuestion(page)
Expand All @@ -645,6 +688,29 @@ const getSmokingQuantityQuestionOverrides = ({
const hasHintOverride = Object.prototype.hasOwnProperty.call(variantInput, 'hint')
const hint = hasHintOverride ? variantInput.hint : question.input.hint
const questionType = variant.type || question.type
const conditionalHref = '#smoking-quantity-other'
const items = variant.options
? variant.options.map((option) => {
const item = toComponentItem(option)

if (!item.conditionalInput) {
return item
}

const conditionalName = step.setting
? `answers[${step.type}][${step.setting}][${item.conditionalInput.answerKey}]`
: `answers[${step.type}][${item.conditionalInput.answerKey}]`

return {
...item,
conditionalInput: {
...item.conditionalInput,
name: conditionalName,
value: conditionalValue
}
}
})
: question.items

return {
type: questionType,
Expand All @@ -659,8 +725,43 @@ const getSmokingQuantityQuestionOverrides = ({
hintParam: hint ? { text: hint } : undefined,
suffix: questionType === 'text' ? smokingType.suffix : undefined
},
validation: variant.validation,
items: variant.options ? variant.options.map(toComponentItem) : question.items,
validation: {
...variant.validation,
conditional: {
another_amount: {
required: true,
type: 'number',
min: 0.5,
max: 24,
answerKey: 'smokingQuantityOther',
value: conditionalValue,
href: conditionalHref
}
}
},
errors: {
conditional: {
another_amount: {
required: {
text: 'Enter the number of hours',
href: conditionalHref
}
}
},
invalid: {
text: 'Number of hours must be a number',
href: conditionalHref
},
min: {
text: 'Number of hours must be 0.5 or more',
href: conditionalHref
},
max: {
text: 'Number of hours must be 24 or fewer',
href: conditionalHref
}
},
items,
value
}
}
Expand Down Expand Up @@ -831,6 +932,7 @@ const getSmokingContentQuestionOverrides = ({
? `answers[${step.type}][${step.setting}][smokingQuantity]`
: `answers[${step.type}][smokingQuantity]`,
value: isSettingSpecific ? settingAnswer.smokingQuantity : answer.smokingQuantity,
conditionalValue: isSettingSpecific ? settingAnswer.smokingQuantityOther : answer.smokingQuantityOther,
smokingType
})
}
Expand Down Expand Up @@ -871,6 +973,7 @@ const getSmokingContentQuestionOverrides = ({
caption: smokingType.caption,
name: `answers[${step.type}][${smokingChange.answerKey}][quantity]`,
value: changeAnswer.quantity,
conditionalValue: changeAnswer.smokingQuantityOther,
smokingType
})
}
Expand Down Expand Up @@ -1012,6 +1115,7 @@ const validateSmokingTypeQuestion = (req, page, step) => {

module.exports = {
deleteUnselectedShishaSettingAnswers,
deleteUnselectedSmokingQuantityOtherAnswer,
deleteUnselectedSmokingChangeAnswers,
deleteUnselectedSmokingTypeAnswers,
formatQuantity,
Expand Down
2 changes: 1 addition & 1 deletion app/prototype_v4_1/views/questions/_question.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
suffix: item.conditionalInput.suffix,
prefix: item.conditionalInput.prefix,
inputmode: item.conditionalInput.inputmode,
value: data.answers[item.conditionalInput.answerKey],
value: item.conditionalInput.value if item.conditionalInput.value is defined else data.answers[item.conditionalInput.answerKey],
classes: item.conditionalInput.classes,
errorMessage: {
text: errorMap[item.conditionalInput.id].text
Expand Down