diff --git a/constants/index.js b/constants/index.js index 5dbc0a399..09a839bac 100644 --- a/constants/index.js +++ b/constants/index.js @@ -8,10 +8,10 @@ function getRopsYears(start) { module.exports = { dateFormat: { - short: 'DD/MM/YYYY', + short: 'D/M/YYYY', medium: 'D MMM YYYY', - long: 'DD MMMM YYYY', - datetime: 'DD MMMM YYYY HH:mm' + long: 'D MMMM YYYY', + datetime: 'D MMMM YYYY HH:mm' }, ropsYears: getRopsYears(2021) }; diff --git a/lib/validation/index.js b/lib/validation/index.js index ac1b8a5d6..bc58afad8 100644 --- a/lib/validation/index.js +++ b/lib/validation/index.js @@ -13,7 +13,7 @@ const defaultValidators = [ } ]; -const validateField = (key, { value, validate }, fields, model) => { +const validateField = (key, { value, validate = [] }, fields, model) => { return validate.reduce((err, options) => { const { validator, params } = options; return err || (!validators[validator](key, value, params, fields, model) && validator); @@ -32,6 +32,7 @@ const validate = (fields, model) => { const normaliseValidators = field => { if (!field.validate) { + field.validate = []; return field; } return { @@ -52,7 +53,7 @@ const normaliseValidators = field => { }; }; -const mapDefaults = (field, key) => { +const mapDefaults = (field) => { const defaults = (defaultValidators.find(v => v.inputType === field.inputType) || {}).validate; return { ...field, @@ -69,9 +70,9 @@ const middleware = (values, schema, model) => { .mapValues(mapDefaults) .pickBy((field, key) => { if (!field.conditionalReveal) { - return field.validate; + return true; } - return values[`conditional-reveal-${key}`] === 'true' && field.validate; + return values[`conditional-reveal-${key}`] === 'true'; }) .value(); diff --git a/package-lock.json b/package-lock.json index f512ac6e0..6b8f7bb9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "@asl/pages", - "version": "31.0.1", + "version": "31.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asl/pages", - "version": "31.0.1", + "version": "31.1.0", "license": "MIT", "dependencies": { "@asl/projects": "^15.0.1", "@asl/service": "^10.0.0", "@joefitter/docx": "^4.7.0", - "@ukhomeoffice/asl-components": "13.0.0", + "@ukhomeoffice/asl-components": "13.2.0", "@ukhomeoffice/asl-constants": "^2.1.0", "@ukhomeoffice/asl-dictionary": "^2.1.0", "@ukhomeoffice/frontend-toolkit": "^3.0.0", @@ -140,6 +140,41 @@ "slate-react": "^0.22.4" } }, + "node_modules/@asl/projects/node_modules/@ukhomeoffice/asl-components": { + "version": "13.0.0", + "resolved": "https://npm.pkg.github.com/download/@ukhomeoffice/asl-components/13.0.0/716829e6e9cc254cabac253725084fb76ca413bd", + "integrity": "sha512-33byjEXUq1dtblvWgBOe7ETehw9h0mAmaRsqLWk4//V3lza+GGdhlclOg4gDtdVQdnjZZ1SFwJmfM3wWEh3MzQ==", + "dependencies": { + "@ukhomeoffice/asl-constants": "^2.0.0", + "@ukhomeoffice/asl-dictionary": "^2.1.0", + "@ukhomeoffice/react-components": "^1.0.0", + "accessible-autocomplete": "^2.0.3", + "babel-plugin-transform-class-properties": "^6.24.1", + "classnames": "^2.2.6", + "date-fns": "^1.29.0", + "diff": "^4.0.1", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "mustache": "^3.0.1", + "qs": "^6.6.1", + "react": "^16.9.0", + "react-markdown": "^6.0.2", + "react-redux": "^7.1.0", + "redux": "^4.0.1", + "remark-breaks": "^2.0.2", + "shasum": "^1.0.2", + "url": "^0.11.0", + "uuid": "^8.3.2" + } + }, + "node_modules/@asl/projects/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/@asl/projects/node_modules/immutable": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", @@ -148,6 +183,17 @@ "node": ">=0.10.0" } }, + "node_modules/@asl/projects/node_modules/mustache": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.2.1.tgz", + "integrity": "sha512-RERvMFdLpaFfSRIEe632yDm5nsd0SDKn8hGmcUwswnyiE5mtdZLDybtHAz6hjJhawokF0hXvGLtx9mrQfm6FkA==", + "bin": { + "mustache": "bin/mustache" + }, + "engines": { + "npm": ">=1.4.0" + } + }, "node_modules/@asl/service": { "version": "10.3.0", "resolved": "https://artifactory.digital.homeoffice.gov.uk/artifactory/api/npm/npm-virtual/@asl/service/-/@asl/service-10.3.0.tgz", @@ -3016,9 +3062,9 @@ "dev": true }, "node_modules/@ukhomeoffice/asl-components": { - "version": "13.0.0", - "resolved": "https://npm.pkg.github.com/download/@ukhomeoffice/asl-components/13.0.0/716829e6e9cc254cabac253725084fb76ca413bd", - "integrity": "sha512-33byjEXUq1dtblvWgBOe7ETehw9h0mAmaRsqLWk4//V3lza+GGdhlclOg4gDtdVQdnjZZ1SFwJmfM3wWEh3MzQ==", + "version": "13.2.0", + "resolved": "https://npm.pkg.github.com/download/@ukhomeoffice/asl-components/13.2.0/88566a0a97f97f20521f1bc6960272aefde49c52", + "integrity": "sha512-+KlGJAapdeFEcgO7SarfoNqNCQ2Q2+etOmmboq3qsw3ziIPCAbpQgi871QiWJNFaFRCQwYCMJsGT2qbGz+pAZg==", "dependencies": { "@ukhomeoffice/asl-constants": "^2.0.0", "@ukhomeoffice/asl-dictionary": "^2.1.0", @@ -7467,9 +7513,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", @@ -16224,10 +16270,47 @@ "slate-schema-violations": "^0.1.39" } }, + "@ukhomeoffice/asl-components": { + "version": "13.0.0", + "resolved": "https://npm.pkg.github.com/download/@ukhomeoffice/asl-components/13.0.0/716829e6e9cc254cabac253725084fb76ca413bd", + "integrity": "sha512-33byjEXUq1dtblvWgBOe7ETehw9h0mAmaRsqLWk4//V3lza+GGdhlclOg4gDtdVQdnjZZ1SFwJmfM3wWEh3MzQ==", + "requires": { + "@ukhomeoffice/asl-constants": "^2.0.0", + "@ukhomeoffice/asl-dictionary": "^2.1.0", + "@ukhomeoffice/react-components": "^1.0.0", + "accessible-autocomplete": "^2.0.3", + "babel-plugin-transform-class-properties": "^6.24.1", + "classnames": "^2.2.6", + "date-fns": "^1.29.0", + "diff": "^4.0.1", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "mustache": "^3.0.1", + "qs": "^6.6.1", + "react": "^16.9.0", + "react-markdown": "^6.0.2", + "react-redux": "^7.1.0", + "redux": "^4.0.1", + "remark-breaks": "^2.0.2", + "shasum": "^1.0.2", + "url": "^0.11.0", + "uuid": "^8.3.2" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, "immutable": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==" + }, + "mustache": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.2.1.tgz", + "integrity": "sha512-RERvMFdLpaFfSRIEe632yDm5nsd0SDKn8hGmcUwswnyiE5mtdZLDybtHAz6hjJhawokF0hXvGLtx9mrQfm6FkA==" } } }, @@ -18411,9 +18494,9 @@ "dev": true }, "@ukhomeoffice/asl-components": { - "version": "13.0.0", - "resolved": "https://npm.pkg.github.com/download/@ukhomeoffice/asl-components/13.0.0/716829e6e9cc254cabac253725084fb76ca413bd", - "integrity": "sha512-33byjEXUq1dtblvWgBOe7ETehw9h0mAmaRsqLWk4//V3lza+GGdhlclOg4gDtdVQdnjZZ1SFwJmfM3wWEh3MzQ==", + "version": "13.2.0", + "resolved": "https://npm.pkg.github.com/download/@ukhomeoffice/asl-components/13.2.0/88566a0a97f97f20521f1bc6960272aefde49c52", + "integrity": "sha512-+KlGJAapdeFEcgO7SarfoNqNCQ2Q2+etOmmboq3qsw3ziIPCAbpQgi871QiWJNFaFRCQwYCMJsGT2qbGz+pAZg==", "requires": { "@ukhomeoffice/asl-constants": "^2.0.0", "@ukhomeoffice/asl-dictionary": "^2.1.0", @@ -21958,9 +22041,9 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==" }, "for-each": { "version": "0.3.3", diff --git a/package.json b/package.json index 0c03d5ca7..49629b3f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asl/pages", - "version": "31.0.1", + "version": "31.1.0", "description": "", "main": "index.js", "style": "pages/common/assets/sass/style.scss", @@ -29,7 +29,7 @@ "@asl/projects": "^15.0.1", "@asl/service": "^10.0.0", "@joefitter/docx": "^4.7.0", - "@ukhomeoffice/asl-components": "13.0.0", + "@ukhomeoffice/asl-components": "13.2.0", "@ukhomeoffice/asl-constants": "^2.1.0", "@ukhomeoffice/asl-dictionary": "^2.1.0", "@ukhomeoffice/frontend-toolkit": "^3.0.0", diff --git a/pages/common/content/index.js b/pages/common/content/index.js index 0e8869734..023419ab0 100644 --- a/pages/common/content/index.js +++ b/pages/common/content/index.js @@ -204,14 +204,14 @@ module.exports = { } }, errors: { - heading: 'Please fix the following error', - headingPlural: 'Please fix the following errors', + heading: 'There is a problem', + headingPlural: 'There is a problem', form: { unchanged: 'No changes have been made', csrf: 'This form data has been changed somewhere else.' }, declaration: { - required: 'Please confirm that you understand.' + required: 'Select to confirm that you understand.' }, default: { maxLength: 'This field is limited to 256 characters', diff --git a/pages/common/routers/form.js b/pages/common/routers/form.js index 712b1af2a..b49f8a696 100644 --- a/pages/common/routers/form.js +++ b/pages/common/routers/form.js @@ -198,7 +198,14 @@ const schemaWithReveals = (schema) => return { ...obj, [key]: value, - ...(value.reveal || {}) + ...(value.reveal || {}), + ...(value.options || []).reduce( + (acc, opt) => ({ + ...acc, + ...(opt.reveal ? schemaWithReveals(opt.reveal) : {}) + }), + {} + ) }; }, {} @@ -242,11 +249,11 @@ module.exports = ({ process = defaultMiddleware, validate = defaultMiddleware, saveValues = defaultMiddleware, - requiresDeclaration = (req) => false, - cancelEdit = (req, res, next) => { + requiresDeclaration = () => false, + cancelEdit = (req, res) => { return res.redirect(cancelPath); }, - editAnswers = (req, res, next) => { + editAnswers = (req, res) => { return res.redirect(req.baseUrl.replace(/\/confirm/, '')); } } = {}) => { diff --git a/pages/establishment/licence-fees/content/index.js b/pages/establishment/licence-fees/content/index.js index 83544e326..cbb3b35e9 100644 --- a/pages/establishment/licence-fees/content/index.js +++ b/pages/establishment/licence-fees/content/index.js @@ -4,7 +4,7 @@ module.exports = { }, fees: { title: 'Estimated licence fees', - period: 'Covering the period:', + period: 'Covering the financial year:', disclaimer: 'These projections are based on the number of billable licences held and may differ from the final numbers.', details: { summary: 'How these fees are calculated', diff --git a/pages/establishment/licence-fees/details/content/index.js b/pages/establishment/licence-fees/details/content/index.js index acf8e3727..346a06626 100644 --- a/pages/establishment/licence-fees/details/content/index.js +++ b/pages/establishment/licence-fees/details/content/index.js @@ -5,22 +5,58 @@ module.exports = merge({}, content, { title: 'Contact information for billing', fields: { contactName: { - label: 'Billing contact' + label: 'Billing contact name' }, contactNumber: { - label: 'Contact number' + label: 'Telephone number' }, contactEmail: { - label: 'Contact email address' + label: 'Email address' }, contactAddress: { label: 'Billing address' }, + hasPurchaseOrder: { + label: 'Do you have a purchase order number?', + options: { + yes: 'Yes', + no: 'No' + } + }, purchaseOrder: { label: 'Purchase order number' }, + alternativePaymentMethod: { + label: 'Provide details for your payment method' + }, otherInformation: { - label: 'Any other billing information' + label: 'Other billing information (optional)' + }, + declaredCurrent: { + label: 'These details are correct for the period {{ currentPeriod }}' + } + }, + errors: { + contactName: { + required: 'Enter a contact name' + }, + contactNumber: { + required: 'Enter a telephone number' + }, + contactEmail: { + required: 'Enter an email address' + }, + contactAddress: { + required: 'Enter an address' + }, + purchaseOrder: { + required: 'Enter a purchase order number' + }, + alternativePaymentMethod: { + required: 'Enter details for your payment method' + }, + declaredCurrent: { + required: 'Select to confirm that all details are up to date' } }, actions: { diff --git a/pages/establishment/licence-fees/details/read/views/index.jsx b/pages/establishment/licence-fees/details/read/views/index.jsx index 7c4d30c66..cb1c64fd6 100644 --- a/pages/establishment/licence-fees/details/read/views/index.jsx +++ b/pages/establishment/licence-fees/details/read/views/index.jsx @@ -3,9 +3,32 @@ import Layout from '../../../views'; import { ModelSummary, Link, Snippet } from '@ukhomeoffice/asl-components'; export default function Details() { + const formatters = { + hasPurchaseOrder: { + format: (value, model) => { + switch (model.hasPurchaseOrder) { + case 'yes': + return 'Yes'; + case 'no': + return 'No'; + default: + return '-'; + } + } + }, + declaredCurrent: { + format: (value, model) => { + return model.declaredCurrent ? 'Yes' : 'No'; + }, + renderContext: { + currentPeriod: '6 April 2024 to 5 April 2025' + } + } + }; + return ( - + actions.editLink}/> ); diff --git a/pages/establishment/licence-fees/details/schema/index.js b/pages/establishment/licence-fees/details/schema/index.js index 08ff6c81f..07d73b522 100644 --- a/pages/establishment/licence-fees/details/schema/index.js +++ b/pages/establishment/licence-fees/details/schema/index.js @@ -1,20 +1,51 @@ module.exports = { contactName: { - inputType: 'inputText' + inputType: 'inputText', + validate: ['required'] }, contactNumber: { - inputType: 'inputText' + inputType: 'inputText', + validate: ['required'] }, contactEmail: { - inputType: 'inputText' + inputType: 'inputText', + validate: ['required'] }, contactAddress: { - inputType: 'textarea' + inputType: 'textarea', + validate: ['required'] }, - purchaseOrder: { - inputType: 'inputText' + hasPurchaseOrder: { + inputType: 'radioGroup', + automapReveals: true, + validate: ['required'], + options: [ + { + value: 'yes', + reveal: { + purchaseOrder: { + inputType: 'inputText', + validate: ['required'] + } + } + }, + { + value: 'no', + reveal: { + alternativePaymentMethod: { + inputType: 'textarea', + validate: ['required'] + } + } + } + ] }, otherInformation: { inputType: 'textarea' + }, + declaredCurrent: { + inputType: 'declaration', + title: 'Confirm that all details are up to date', + validate: ['required'] } }; diff --git a/pages/establishment/licence-fees/details/update/content/index.js b/pages/establishment/licence-fees/details/update/content/index.js index 9465fc456..4f8b86746 100644 --- a/pages/establishment/licence-fees/details/update/content/index.js +++ b/pages/establishment/licence-fees/details/update/content/index.js @@ -1,7 +1,4 @@ const { merge } = require('lodash'); const content = require('../../content'); -module.exports = merge({}, content, { - intro: 'These details can be used for any contact regarding billing or finances.', - inset: 'All fields are optional.' -}); +module.exports = merge({}, content, {}); diff --git a/pages/establishment/licence-fees/details/update/views/index.jsx b/pages/establishment/licence-fees/details/update/views/index.jsx index a50f1ed6a..1f3a44815 100644 --- a/pages/establishment/licence-fees/details/update/views/index.jsx +++ b/pages/establishment/licence-fees/details/update/views/index.jsx @@ -1,20 +1,24 @@ import React from 'react'; import { useSelector } from 'react-redux'; -import { FormLayout, Header, Snippet, Inset } from '@ukhomeoffice/asl-components'; +import { FormLayout, Header, Snippet } from '@ukhomeoffice/asl-components'; import EstablishmentHeader from '../../../../../common/components/establishment-header'; export default function Details() { const establishment = useSelector(state => state.static.establishment); + const formatters = { + declaredCurrent: { + renderContext: { + currentPeriod: '6 April 2024 to 5 April 2025' + } + } + }; + return ( - +
title} subtitle={} /> - intro - - inset - ); } diff --git a/pages/establishment/licence-fees/views/index.jsx b/pages/establishment/licence-fees/views/index.jsx index ca54d345f..6274341af 100644 --- a/pages/establishment/licence-fees/views/index.jsx +++ b/pages/establishment/licence-fees/views/index.jsx @@ -94,7 +94,7 @@ export default function Fees({ tab, tabs, children, subtitle = '' }) { className="inline" onChange={onYearSelect} value={year} - nullOption={false} + nullOption={null} /> fees.disclaimer