Skip to content

Commit

Permalink
Saving input from return requirements in session (#939)
Browse files Browse the repository at this point in the history
* Saving input from return requirements in session

During the initial development of the return requirements pages, user input
was not being saved in session. Later tickets and pages have this functionality in place.
The session data is needed for the Check Your Answers page at the end of the journey.

This PR is focused on saving user input into the session where it is missing.
  • Loading branch information
rvsiyad authored Apr 30, 2024
1 parent 64a23d1 commit 3dcb83c
Show file tree
Hide file tree
Showing 33 changed files with 354 additions and 311 deletions.
22 changes: 3 additions & 19 deletions app/presenters/return-requirements/abstraction-period.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,20 @@
* Formats data for the `/return-requirements/{sessionId}/abstraction-period` page
*
* @param {module:SessionModel} session - The returns requirements session instance
* @param {Object} [payload] - The payload from the request
*
* @returns {Object} - The data formatted for the view template
*/
function go (session, payload = {}) {
function go (session) {
const data = {
abstractionPeriod: session.data.abstractionPeriod ? session.data.abstractionPeriod : null,
id: session.id,
licenceId: session.data.licence.id,
licenceRef: session.data.licence.licenceRef,
abstractionPeriod: _licenceAbstractionPeriod(payload)
licenceRef: session.data.licence.licenceRef
}

return data
}

function _licenceAbstractionPeriod (payload) {
// NOTE: The following checks whether a user has inputted any values for the abstraction period for the returns
// requirements. If the values have not been set, then it is because the presenter has been called from
// 'AbstractionPeriodService' and it's the first load. Else it has been called by the 'SubmitAbstractionPeriod' and
// the user has not inputted any values for the abstraction period. Either way, we use it to tell us wether there is
// anything in the payload worth transforming.

return {
startDay: payload['start-abstraction-period-day'] ? payload['start-abstraction-period-day'] : null,
startMonth: payload['start-abstraction-period-month'] ? payload['start-abstraction-period-month'] : null,
endDay: payload['end-abstraction-period-day'] ? payload['end-abstraction-period-day'] : null,
endMonth: payload['end-abstraction-period-month'] ? payload['end-abstraction-period-month'] : null
}
}

module.exports = {
go
}
19 changes: 4 additions & 15 deletions app/presenters/return-requirements/points.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,22 @@
*
* @param {module:SessionModel} session - The returns requirements session instance
* @param {Object} [pointsData] - The points for the licence
* @param {Object} [payload] - The payload from the request
*
* @returns {Object} - The data formatted for the view template
*/
function go (session, pointsData, payload = {}) {
function go (session, pointsData) {
const data = {
id: session.id,
licenceId: session.data.licence.id,
licenceRef: session.data.licence.licenceRef,
licencePoints: _licencePoints(pointsData, payload)
licencePoints: _licencePoints(pointsData),
selectedPoints: session.data.points ? session.data.points.join(',') : ''
}

return data
}

function _licencePoints (pointsData, payload) {
// NOTE: 'points' is the payload value that tells us whether the user selected any purposes
// for the return requirement.
// If it is not set then it is because the presenter has been called from 'PointsService' and it's the first
// load. Else it has been called by the 'SubmitPointsService' and the user has not checked a point from the list.
// Either way, we use it to tell us whether there is anything in the payload worth transforming.
const points = payload.points

if (points) {
return points
}

function _licencePoints (pointsData) {
const abstractionPoints = []

if (!pointsData) {
Expand Down
3 changes: 2 additions & 1 deletion app/presenters/return-requirements/reason.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
function go (session) {
const data = {
id: session.id,
licenceRef: session.data.licence.licenceRef
licenceRef: session.data.licence.licenceRef,
reason: session.data.reason ? session.data.reason : null
}

return data
Expand Down
3 changes: 2 additions & 1 deletion app/presenters/return-requirements/setup.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
function go (session) {
const data = {
id: session.id,
licenceRef: session.data.licence.licenceRef
licenceRef: session.data.licence.licenceRef,
setup: session.data.setup ? session.data.setup : null
}

return data
Expand Down
19 changes: 2 additions & 17 deletions app/presenters/return-requirements/site-description.presenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,17 @@
*
* @returns {Object} - The data formatted for the view template
*/
function go (session, payload = {}) {
function go (session) {
const data = {
id: session.id,
licenceId: session.data.licence.id,
licenceRef: session.data.licence.licenceRef,
licenceSiteDescription: _licenceSiteDescription(payload)
siteDescription: session.data.siteDescription ? session.data.siteDescription : null
}

return data
}

function _licenceSiteDescription (payload) {
// NOTE: 'siteDescription' is the payload value that tells us whether the user inputted a siteDescription
// for the return requirement site.
// If it is not set then it is because the presenter has been called from 'SiteDescriptionService' and it's the first
// load. Else it has been called by the 'SubmitSiteDescriptionService' and the user has not inputted a site description.
// Either way, we use it to tell us wether there is anything in the payload worth transforming.
const siteDescription = payload.siteDescription

if (!siteDescription) {
return null
}

return siteDescription
}

module.exports = {
go
}
4 changes: 2 additions & 2 deletions app/services/return-requirements/points.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

const FetchPointsService = require('../../services/return-requirements/fetch-points.service.js')
const SelectPointsPresenter = require('../../presenters/return-requirements/points.presenter.js')
const PointsPresenter = require('../../presenters/return-requirements/points.presenter.js')
const SessionModel = require('../../models/session.model.js')

/**
Expand All @@ -23,7 +23,7 @@ async function go (sessionId) {
const session = await SessionModel.query().findById(sessionId)
const pointsData = await FetchPointsService.go(session.data.licence.id)

const formattedData = SelectPointsPresenter.go(session, pointsData)
const formattedData = PointsPresenter.go(session, pointsData)

return {
activeNavBar: 'search',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ async function go (sessionId, payload) {
return {}
}

const formattedData = AbstractionPeriodPresenter.go(session, payload)
const submittedSessionData = _submittedSessionData(session, payload)

return {
activeNavBar: 'search',
error: validationResult,
pageTitle: 'Enter the abstraction period for the requirements for returns',
...formattedData
...submittedSessionData
}
}

Expand All @@ -52,6 +52,16 @@ async function _save (session, payload) {
return session.$query().patch({ data: currentData })
}

/**
* Combines the existing session data with the submitted payload formatted by the presenter. If nothing is submitted by
* the user, payload will be an empty object.
*/
function _submittedSessionData (session, payload) {
session.data.abstractionPeriod = Object.keys(payload).length > 0 ? payload : null

return AbstractionPeriodPresenter.go(session)
}

function _validate (payload) {
const validation = AbstractionPeriodValidator.go(payload)

Expand Down
34 changes: 31 additions & 3 deletions app/services/return-requirements/submit-points.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

const FetchPointsService = require('../../services/return-requirements/fetch-points.service.js')
const PointsValidator = require('../../validators/return-requirements/points.validator.js')
const SelectPointsPresenter = require('../../presenters/return-requirements/points.presenter.js')
const PointsPresenter = require('../../presenters/return-requirements/points.presenter.js')
const SessionModel = require('../../models/session.model.js')

/**
Expand All @@ -27,9 +27,18 @@ const SessionModel = require('../../models/session.model.js')
async function go (sessionId, payload) {
const session = await SessionModel.query().findById(sessionId)

const pointsData = await FetchPointsService.go(session.data.licence.id)
_handleOneOptionSelected(payload)

const validationResult = _validate(payload)
const formattedData = SelectPointsPresenter.go(session, pointsData, payload)

if (!validationResult) {
await _save(session, payload)

return {}
}

const pointsData = await FetchPointsService.go(session.data.licence.id)
const formattedData = PointsPresenter.go(session, pointsData)

return {
activeNavBar: 'search',
Expand All @@ -39,6 +48,25 @@ async function go (sessionId, payload) {
}
}

/**
* When a single point is checked by the user, it returns as a string. When multiple points are checked, the
* 'points' is returned as an array. This function works to make those single selected string 'points' into an array
* for uniformity.
*/
function _handleOneOptionSelected (payload) {
if (!Array.isArray(payload.points)) {
payload.points = [payload.points]
}
}

async function _save (session, payload) {
const currentData = session.data

currentData.points = payload.points

return session.$query().patch({ data: currentData })
}

function _validate (payload) {
const validation = PointsValidator.go(payload)

Expand Down
10 changes: 5 additions & 5 deletions app/services/return-requirements/submit-purpose.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@

const FetchPurposesService = require('../../services/return-requirements/fetch-purposes.service.js')
const PurposeValidation = require('../../validators/return-requirements/purpose.validator.js')
const SelectPurposePresenter = require('../../presenters/return-requirements/purpose.presenter.js')
const PurposePresenter = require('../../presenters/return-requirements/purpose.presenter.js')
const SessionModel = require('../../models/session.model.js')

/**
* Orchestrates validating the data for `/return-requirements/{sessionId}/purpose` page
*
* It first retrieves the session instance for the returns requirements journey in progress.
*
* The user input is then validated and the result is then combined with the output of the presenter to generate the page data needed by the view.
* If there was a validation error the controller will re-render the page so needs this information. If all is well the
* controller will redirect to the next page in the journey.
* The user input is then validated and the result is then combined with the output of the presenter to generate the
* page data needed by the view. If there was a validation error the controller will re-render the page so needs this
* information. If all is well the controller will redirect to the next page in the journey.
*
* @param {string} sessionId - The id of the current session
* @param {Object} payload - The submitted form data
Expand All @@ -38,7 +38,7 @@ async function go (sessionId, payload) {
}

const purposesData = await FetchPurposesService.go(session.data.licence.id)
const formattedData = SelectPurposePresenter.go(session, purposesData)
const formattedData = PurposePresenter.go(session, purposesData)

return {
activeNavBar: 'search',
Expand Down
4 changes: 2 additions & 2 deletions app/services/return-requirements/submit-setup.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ async function go (sessionId, payload) {
function _redirect (setup) {
let endpoint

if (setup === 'use_abstraction_data') {
if (setup === 'use-abstraction-data') {
endpoint = 'check-your-answers'
}

if (setup === 'set_up_manually') {
if (setup === 'set-up-manually') {
endpoint = 'purpose'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ const SiteDescriptionValidator = require('../../validators/return-requirements/s
*
* It first retrieves the session instance for the returns requirements journey in progress.
*
* The user input is then validated and the result is then combined with the output of the presenter to generate the page data needed by the view.
* If there was a validation error the controller will re-render the page so needs this information. If all is well the
* controller will redirect to the next page in the journey.
* The user input is then validated and the site description in the payload is saved in the session. If there is a
* validation error the controller will re-render the page. If all is well the controller will redirect to the next page
* in the journey.
*
* @param {string} sessionId - The id of the current session
* @param {string} sessionId - The UUID of the current session
* @param {Object} payload - The submitted form data
*
* @returns {Promise<Object>} The page data for the start date page
Expand All @@ -28,17 +28,40 @@ async function go (sessionId, payload) {

const validationResult = _validate(payload)

const formattedData = SiteDescriptionPresenter.go(session, payload)
if (!validationResult) {
await _save(session, payload)

return {}
}

const submittedSessionData = _submittedSessionData(session, payload)

return {
activeNavBar: 'search',
error: validationResult,
journey: session.data.journey,
pageTitle: 'Enter a site description for the requirements for returns',
...formattedData
...submittedSessionData
}
}

async function _save (session, payload) {
const currentData = session.data

currentData.siteDescription = payload.siteDescription

return session.$query().patch({ data: currentData })
}

/**
* Combines the existing session data with the submitted payload formatted by the presenter. If nothing is submitted by
* the user, payload will be an empty object.
*/
function _submittedSessionData (session, payload) {
session.data.siteDescription = payload.siteDescription ? payload.siteDescription : null

return SiteDescriptionPresenter.go(session)
}

function _validate (payload) {
const validation = SiteDescriptionValidator.go(payload)

Expand Down
4 changes: 2 additions & 2 deletions app/validators/return-requirements/setup.validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
const Joi = require('joi')

const VALID_VALUES = [
'use_abstraction_data',
'set_up_manually'
'use-abstraction-data',
'set-up-manually'
]

/**
Expand Down
12 changes: 8 additions & 4 deletions app/views/return-requirements/abstraction-period.njk
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@
items: [
{
name: "day",
classes: "govuk-input--width-2" + startResultErrorClass
classes: "govuk-input--width-2" + startResultErrorClass,
value: abstractionPeriod['start-abstraction-period-day']
},
{
name: "month",
classes: "govuk-input--width-2" + startResultErrorClass
classes: "govuk-input--width-2" + startResultErrorClass,
value: abstractionPeriod['start-abstraction-period-month']
}
]
}) }}
Expand All @@ -96,11 +98,13 @@
items: [
{
name: "day",
classes: "govuk-input--width-2" + endResultErrorClass
classes: "govuk-input--width-2" + endResultErrorClass,
value: abstractionPeriod['end-abstraction-period-day']
},
{
name: "month",
classes: "govuk-input--width-2" + endResultErrorClass
classes: "govuk-input--width-2" + endResultErrorClass,
value: abstractionPeriod['end-abstraction-period-month']
}
]
}) }}
Expand Down
2 changes: 1 addition & 1 deletion app/views/return-requirements/points.njk
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
{% set checkBoxItem = {
value: point,
text: point,
checked: false
checked: point in selectedPoints
} %}

{% set checkBoxItems = (checkBoxItems.push(checkBoxItem), checkBoxItems) %}
Expand Down
Loading

0 comments on commit 3dcb83c

Please sign in to comment.