diff --git a/src/client/stylesheets/_location-input.scss b/src/client/stylesheets/_location-input.scss deleted file mode 100644 index 5cf52f72b..000000000 --- a/src/client/stylesheets/_location-input.scss +++ /dev/null @@ -1,60 +0,0 @@ -@use "govuk-frontend" as *; - -.app-location-input { - @include govuk-clearfix; - font-size: 0; // removes whitespace caused by inline-block - margin-bottom: govuk-spacing(6); - - &:has(.govuk-input--error) { - border-left: $govuk-border-width-form-group-error solid $govuk-error-colour; - padding-left: govuk-spacing(3); - margin-top: 0; - } -} - -.govuk-hint:has(+ .app-location-input .govuk-input--error) { - border-left: $govuk-border-width-form-group-error solid $govuk-error-colour; - padding-left: govuk-spacing(3); - margin-bottom: 0; -} - -.govuk-fieldset:has(.app-location-input .govuk-input--error) { - .govuk-fieldset__legend { - border-left: $govuk-border-width-form-group-error solid $govuk-error-colour; - padding-left: govuk-spacing(3); - margin-bottom: 0; - } - - .govuk-fieldset__legend + .govuk-hint { - margin-top: 0; - } -} - -.app-location-input__item { - display: inline-block; - margin-right: govuk-spacing(4); - margin-bottom: govuk-spacing(4); - - &:last-child { - margin-right: 0; - } - - @include govuk-media-query($from: tablet) { - margin-bottom: 0; - } - - .govuk-form-group { - margin-bottom: 0; - display: inline-block; - width: auto; - } - - .govuk-label { - display: block; - } - - .govuk-input { - margin-bottom: 0; - width: auto; - } -} diff --git a/src/client/stylesheets/application.scss b/src/client/stylesheets/application.scss index bb90268a1..349c344c2 100644 --- a/src/client/stylesheets/application.scss +++ b/src/client/stylesheets/application.scss @@ -2,7 +2,6 @@ @use "shared"; @use "code"; @use "tag-env"; -@use "location-input"; // An example of some user-supplied styling // Not great practice but it illustrates the point diff --git a/src/client/stylesheets/shared.scss b/src/client/stylesheets/shared.scss index daeadccba..cb7277959 100644 --- a/src/client/stylesheets/shared.scss +++ b/src/client/stylesheets/shared.scss @@ -2,7 +2,6 @@ @use "pkg:accessible-autocomplete"; @use "prose"; @use "summary-list"; -@use "location-input"; // Use default GDS Transport font for autocomplete .autocomplete__hint, diff --git a/src/server/forms/register-as-a-unicorn-breeder.yaml b/src/server/forms/register-as-a-unicorn-breeder.yaml index 2263aebfc..ff8408dde 100644 --- a/src/server/forms/register-as-a-unicorn-breeder.yaml +++ b/src/server/forms/register-as-a-unicorn-breeder.yaml @@ -168,15 +168,17 @@ pages: schema: {} type: EastingNorthingField title: Easting and northing + shortDescription: Location hint: This is an Easting and Northing component - name: seTThb options: {} schema: {} type: LatLongField - title: Latitute and longitude + title: Latitude and longitude + shortDescription: Position hint: - This is an Latitute and Longitude component + This is an Latitude and Longitude component - name: bhjloS options: {} schema: {} diff --git a/src/server/plugins/engine/components/EastingNorthingField.test.ts b/src/server/plugins/engine/components/EastingNorthingField.test.ts index 8cbebf244..3777eb7b1 100644 --- a/src/server/plugins/engine/components/EastingNorthingField.test.ts +++ b/src/server/plugins/engine/components/EastingNorthingField.test.ts @@ -335,7 +335,7 @@ describe('EastingNorthingField', () => { expect(instructionText).toContain('meters') }) - it('sets error classes when component has errors', () => { + it('handles errors when component has validation errors', () => { const payload = getFormData({ easting: '', northing: '' @@ -352,15 +352,21 @@ describe('EastingNorthingField', () => { const viewModel = field.getViewModel(payload, errors) + // Check that error is passed to the viewModel + expect(viewModel.errors).toEqual(errors) + + // Items should be present with their basic structure expect(viewModel.items?.[0]).toEqual( expect.objectContaining({ - classes: expect.stringContaining('govuk-input--error') + id: 'myComponent__easting', + name: 'myComponent__easting' }) ) expect(viewModel.items?.[1]).toEqual( expect.objectContaining({ - classes: expect.stringContaining('govuk-input--error') + id: 'myComponent__northing', + name: 'myComponent__northing' }) ) }) diff --git a/src/server/plugins/engine/components/EastingNorthingField.ts b/src/server/plugins/engine/components/EastingNorthingField.ts index 2a48efc08..cf26d456b 100644 --- a/src/server/plugins/engine/components/EastingNorthingField.ts +++ b/src/server/plugins/engine/components/EastingNorthingField.ts @@ -3,6 +3,7 @@ import { type EastingNorthingFieldComponent } from '@defra/forms-model' import { type LanguageMessages, type ObjectSchema } from 'joi' +import lowerFirst from 'lodash/lowerFirst.js' import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js' import { @@ -57,22 +58,22 @@ export class EastingNorthingField extends FormComponent { convertToLanguageMessages({ 'any.required': messageTemplate.objectMissing, 'number.base': messageTemplate.objectMissing, - 'number.min': `{{#label}} for ${this.title} must be between {{#limit}} and ${eastingMax}`, - 'number.max': `{{#label}} for ${this.title} must be between ${eastingMin} and {{#limit}}`, - 'number.precision': `{{#label}} for ${this.title} must be between 1 and 6 digits`, - 'number.integer': `{{#label}} for ${this.title} must be between 1 and 6 digits`, - 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 6 digits` + 'number.min': `{{#label}} for ${lowerFirst(this.label)} must be between {{#limit}} and ${eastingMax}`, + 'number.max': `{{#label}} for ${lowerFirst(this.label)} must be between ${eastingMin} and {{#limit}}`, + 'number.precision': `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 6 digits`, + 'number.integer': `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 6 digits`, + 'number.unsafe': `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 6 digits` }) const northingValidationMessages: LanguageMessages = convertToLanguageMessages({ 'any.required': messageTemplate.objectMissing, 'number.base': messageTemplate.objectMissing, - 'number.min': `{{#label}} for ${this.title} must be between {{#limit}} and ${northingMax}`, - 'number.max': `{{#label}} for ${this.title} must be between ${northingMin} and {{#limit}}`, - 'number.precision': `{{#label}} for ${this.title} must be between 1 and 7 digits`, - 'number.integer': `{{#label}} for ${this.title} must be between 1 and 7 digits`, - 'number.unsafe': `{{#label}} for ${this.title} must be between 1 and 7 digits` + 'number.min': `{{#label}} for ${lowerFirst(this.label)} must be between {{#limit}} and ${northingMax}`, + 'number.max': `{{#label}} for ${lowerFirst(this.label)} must be between ${northingMin} and {{#limit}}`, + 'number.precision': `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 7 digits`, + 'number.integer': `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 7 digits`, + 'number.unsafe': `{{#label}} for ${lowerFirst(this.label)} must be between 1 and 7 digits` }) this.collection = new ComponentCollection( @@ -198,11 +199,11 @@ export class EastingNorthingField extends FormComponent { advancedSettingsErrors: [ { type: 'eastingMin', - template: `Easting for [short description] must be between 0 and 700000` + template: `Easting for [short description] must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}` }, { type: 'eastingMax', - template: `Easting for [short description] must be between 0 and 700000` + template: `Easting for [short description] must be between ${DEFAULT_EASTING_MIN} and ${DEFAULT_EASTING_MAX}` }, { type: 'northingMin', diff --git a/src/server/plugins/engine/components/LatLongField.test.ts b/src/server/plugins/engine/components/LatLongField.test.ts index 6536506f6..57bac38e4 100644 --- a/src/server/plugins/engine/components/LatLongField.test.ts +++ b/src/server/plugins/engine/components/LatLongField.test.ts @@ -324,7 +324,7 @@ describe('LatLongField', () => { expect(instructionText).toContain('decimal') }) - it('sets error classes when component has errors', () => { + it('handles errors when component has validation errors', () => { const payload = getFormData({ latitude: '', longitude: '' @@ -341,15 +341,21 @@ describe('LatLongField', () => { const viewModel = field.getViewModel(payload, errors) + // Check that error is passed to the viewModel + expect(viewModel.errors).toEqual(errors) + + // Items should be present with their basic structure expect(viewModel.items?.[0]).toEqual( expect.objectContaining({ - classes: expect.stringContaining('govuk-input--error') + id: 'myComponent__latitude', + name: 'myComponent__latitude' }) ) expect(viewModel.items?.[1]).toEqual( expect.objectContaining({ - classes: expect.stringContaining('govuk-input--error') + id: 'myComponent__longitude', + name: 'myComponent__longitude' }) ) }) diff --git a/src/server/plugins/engine/components/LatLongField.ts b/src/server/plugins/engine/components/LatLongField.ts index f90beb541..fe43d3e1d 100644 --- a/src/server/plugins/engine/components/LatLongField.ts +++ b/src/server/plugins/engine/components/LatLongField.ts @@ -1,5 +1,6 @@ import { ComponentType, type LatLongFieldComponent } from '@defra/forms-model' import { type LanguageMessages, type ObjectSchema } from 'joi' +import lowerFirst from 'lodash/lowerFirst.js' import { ComponentCollection } from '~/src/server/plugins/engine/components/ComponentCollection.js' import { @@ -60,16 +61,16 @@ export class LatLongField extends FormComponent { const latitudeMessages: LanguageMessages = convertToLanguageMessages({ ...customValidationMessages, - 'number.base': `Enter a valid latitude for ${this.title} like 51.519450`, - 'number.min': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}`, - 'number.max': `Latitude for ${this.title} must be between ${latitudeMin} and ${latitudeMax}` + 'number.base': `Enter a valid latitude for ${lowerFirst(this.label)} like 51.519450`, + 'number.min': `Latitude for ${lowerFirst(this.label)} must be between ${latitudeMin} and ${latitudeMax}`, + 'number.max': `Latitude for ${lowerFirst(this.label)} must be between ${latitudeMin} and ${latitudeMax}` }) const longitudeMessages: LanguageMessages = convertToLanguageMessages({ ...customValidationMessages, - 'number.base': `Enter a valid longitude for ${this.title} like -0.127758`, - 'number.min': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}`, - 'number.max': `Longitude for ${this.title} must be between ${longitudeMin} and ${longitudeMax}` + 'number.base': `Enter a valid longitude for ${lowerFirst(this.label)} like -0.127758`, + 'number.min': `Longitude for ${lowerFirst(this.label)} must be between ${longitudeMin} and ${longitudeMax}`, + 'number.max': `Longitude for ${lowerFirst(this.label)} must be between ${longitudeMin} and ${longitudeMax}` }) this.collection = new ComponentCollection( diff --git a/src/server/plugins/engine/components/LocationFieldHelpers.test.ts b/src/server/plugins/engine/components/LocationFieldHelpers.test.ts index 3adf8fee7..1cf77a087 100644 --- a/src/server/plugins/engine/components/LocationFieldHelpers.test.ts +++ b/src/server/plugins/engine/components/LocationFieldHelpers.test.ts @@ -71,7 +71,7 @@ describe('LocationFieldHelpers', () => { expect(instructionText).toContain('decimal format') }) - it('should add error classes to items when component has errors', () => { + it('should handle component-level errors correctly', () => { const def: LatLongFieldComponent = { title: 'Example lat long', name: 'myComponent', @@ -99,20 +99,26 @@ describe('LocationFieldHelpers', () => { const viewModel = field.getViewModel(payload, errors) + // Check that errors are passed to the viewModel + expect(viewModel.errors).toEqual(errors) + + // Items should still have their structure expect(viewModel.items[0]).toEqual( expect.objectContaining({ - classes: expect.stringContaining('govuk-input--error') + id: 'myComponent__latitude', + name: 'myComponent__latitude' }) ) expect(viewModel.items[1]).toEqual( expect.objectContaining({ - classes: expect.stringContaining('govuk-input--error') + id: 'myComponent__longitude', + name: 'myComponent__longitude' }) ) }) - it('should add error classes to items when subfield has errors', () => { + it('should pass error messages to individual items when subfield has errors', () => { const def: LatLongFieldComponent = { title: 'Example lat long', name: 'myComponent', @@ -140,9 +146,12 @@ describe('LocationFieldHelpers', () => { const viewModel = field.getViewModel(payload, errors) + // Check that errorMessage is passed through to the item expect(viewModel.items[0]).toEqual( expect.objectContaining({ - classes: expect.stringContaining('govuk-input--error') + errorMessage: { + text: 'Invalid latitude' + } }) ) }) diff --git a/src/server/plugins/engine/components/LocationFieldHelpers.ts b/src/server/plugins/engine/components/LocationFieldHelpers.ts index ec721df2c..7e1e70a0a 100644 --- a/src/server/plugins/engine/components/LocationFieldHelpers.ts +++ b/src/server/plugins/engine/components/LocationFieldHelpers.ts @@ -30,12 +30,9 @@ export function getLocationFieldViewModel( payload: FormPayload, errors?: FormSubmissionError[] ) { - const { collection, name } = component + const { collection } = component const { fieldset: existingFieldset, label } = viewModel - // Check for component errors only - const hasError = errors?.some((error) => error.name === name) - // Use the component collection to generate the subitems const items: DateInputItem[] = collection .getViewModel(payload, errors) @@ -46,10 +43,6 @@ export function getLocationFieldViewModel( label.toString = () => label.text // Use string labels } - if (hasError || errorMessage) { - classes = `${classes ?? ''} govuk-input--error`.trim() - } - // Allow any `toString()`-able value so non-numeric // values are shown alongside their error messages if (!isFormValue(value)) { @@ -64,7 +57,8 @@ export function getLocationFieldViewModel( value, classes, prefix, - suffix + suffix, + errorMessage } }) diff --git a/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts b/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts index 2f52ca83d..00a67d634 100644 --- a/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts +++ b/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts @@ -103,23 +103,15 @@ describe('NationalGridFieldNumberField', () => { const result1 = collection.validate(getFormData('TQ12345678')) const result2 = collection.validate(getFormData('TQ 1234 5678')) - // Test 10-digit OS grid reference format (2x5) - const result3 = collection.validate(getFormData('SU1234567890')) - const result4 = collection.validate(getFormData('SU 12345 67890')) - expect(result1.errors).toBeUndefined() expect(result2.errors).toBeUndefined() - expect(result3.errors).toBeUndefined() - expect(result4.errors).toBeUndefined() // Test case-insensitive - const result5 = collection.validate(getFormData('nt12345678')) + const result3 = collection.validate(getFormData('nt12345678')) expect(result1.errors).toBeUndefined() expect(result2.errors).toBeUndefined() expect(result3.errors).toBeUndefined() - expect(result4.errors).toBeUndefined() - expect(result5.errors).toBeUndefined() }) it('formats values with spaces per GDS guidance', () => { @@ -265,6 +257,7 @@ describe('NationalGridFieldNumberField', () => { description: 'Trim empty spaces', component: { title: 'Example National Grid field number', + shortDescription: 'Grid field', name: 'myComponent', type: ComponentType.NationalGridFieldNumberField, options: {} @@ -288,6 +281,7 @@ describe('NationalGridFieldNumberField', () => { description: 'Pattern validation', component: { title: 'Example National Grid field number', + shortDescription: 'Grid field', name: 'myComponent', type: ComponentType.NationalGridFieldNumberField, options: {} @@ -299,7 +293,7 @@ describe('NationalGridFieldNumberField', () => { value: getFormData('NG1234567'), errors: expect.arrayContaining([ expect.objectContaining({ - text: 'Enter a valid National Grid field number for Example National Grid field number like NG 1234 5678' + text: 'Enter a valid National Grid field number for grid field like NG 1234 5678' }) ]) } @@ -310,7 +304,7 @@ describe('NationalGridFieldNumberField', () => { value: getFormData('N123456789'), errors: expect.arrayContaining([ expect.objectContaining({ - text: 'Enter a valid National Grid field number for Example National Grid field number like NG 1234 5678' + text: 'Enter a valid National Grid field number for grid field like NG 1234 5678' }) ]) } @@ -321,7 +315,7 @@ describe('NationalGridFieldNumberField', () => { value: getFormData('NGABCDEFGH'), errors: expect.arrayContaining([ expect.objectContaining({ - text: 'Enter a valid National Grid field number for Example National Grid field number like NG 1234 5678' + text: 'Enter a valid National Grid field number for grid field like NG 1234 5678' }) ]) } @@ -332,6 +326,7 @@ describe('NationalGridFieldNumberField', () => { description: 'Custom validation message', component: { title: 'Example National Grid field number', + shortDescription: 'Grid field', name: 'myComponent', type: ComponentType.NationalGridFieldNumberField, options: { @@ -367,6 +362,7 @@ describe('NationalGridFieldNumberField', () => { description: 'Custom validation messages (multiple)', component: { title: 'Example National Grid field number', + shortDescription: 'Grid field', name: 'myComponent', type: ComponentType.NationalGridFieldNumberField, options: { @@ -417,6 +413,7 @@ describe('NationalGridFieldNumberField', () => { description: 'Optional field', component: { title: 'Example National Grid field number', + shortDescription: 'Grid field', name: 'myComponent', type: ComponentType.NationalGridFieldNumberField, options: { diff --git a/src/server/plugins/engine/components/NationalGridFieldNumberField.ts b/src/server/plugins/engine/components/NationalGridFieldNumberField.ts index 19400d7e4..6272cb25a 100644 --- a/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +++ b/src/server/plugins/engine/components/NationalGridFieldNumberField.ts @@ -1,4 +1,5 @@ import { type NationalGridFieldNumberFieldComponent } from '@defra/forms-model' +import lowerFirst from 'lodash/lowerFirst.js' import { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js' @@ -6,16 +7,15 @@ export class NationalGridFieldNumberField extends LocationFieldBase { declare options: NationalGridFieldNumberFieldComponent['options'] protected getValidationConfig() { - // Regex for OS grid references and parcel IDs + // Regex for OS national grid field references (NGFR) // Validates specific valid OS grid letter combinations with: - // - 2 letters & 8 digits in 2 blocks of 4 (parcel ID) e.g., ST 6789 6789 - // - 2 letters & 10 digits in 2 blocks of 5 (OS grid reference) e.g., SO 12345 12345 + // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789 const pattern = - /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?(([0-9]{4})\s?([0-9]{4})|([0-9]{5})\s?([0-9]{5}))$/ + /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?([0-9]{4})\s?([0-9]{4})$/ return { pattern, - patternErrorMessage: `Enter a valid National Grid field number for ${this.title} like NG 1234 5678` + patternErrorMessage: `Enter a valid National Grid field number for ${lowerFirst(this.label)} like NG 1234 5678` } } diff --git a/src/server/plugins/engine/components/OsGridRefField.test.ts b/src/server/plugins/engine/components/OsGridRefField.test.ts index 3af774b35..9183fb081 100644 --- a/src/server/plugins/engine/components/OsGridRefField.test.ts +++ b/src/server/plugins/engine/components/OsGridRefField.test.ts @@ -100,12 +100,22 @@ describe('OsGridRefField', () => { const result1 = collection.validate(getFormData('SD865005')) const result2 = collection.validate(getFormData('SD 865 005')) + const result3 = collection.validate(getFormData('SD86565005')) + const result4 = collection.validate(getFormData('SD 8656 0065')) + + const result5 = collection.validate(getFormData('SD8654454005')) + const result6 = collection.validate(getFormData('SD 86455 00545')) + // Test case-insensitive - const result3 = collection.validate(getFormData('nt123456')) + const result7 = collection.validate(getFormData('nt123456')) expect(result1.errors).toBeUndefined() expect(result2.errors).toBeUndefined() expect(result3.errors).toBeUndefined() + expect(result4.errors).toBeUndefined() + expect(result5.errors).toBeUndefined() + expect(result6.errors).toBeUndefined() + expect(result7.errors).toBeUndefined() }) it('retains values with spaces per GDS guidance', () => { @@ -137,8 +147,9 @@ describe('OsGridRefField', () => { const result4 = collection.validate(getFormData('TQ1234567')) // Wrong number of digits (7) // Test mismatched digit counts (must be either 3+3, 4+4 or 5+5, not mixed) - const result5 = collection.validate(getFormData('SN 4444 55555')) // mismatched digit counts - const result6 = collection.validate(getFormData('SN 55555 4444')) // mismatched digit counts + const result5 = collection.validate(getFormData('SN 333 4444')) // mismatched digit counts + const result6 = collection.validate(getFormData('SN 4444 55555')) // mismatched digit counts + const result7 = collection.validate(getFormData('SN 55555 4444')) // mismatched digit counts expect(result1.errors).toBeTruthy() expect(result2.errors).toBeTruthy() @@ -146,6 +157,7 @@ describe('OsGridRefField', () => { expect(result4.errors).toBeTruthy() expect(result5.errors).toBeTruthy() expect(result6.errors).toBeTruthy() + expect(result7.errors).toBeTruthy() }) }) @@ -284,6 +296,7 @@ describe('OsGridRefField', () => { description: 'Pattern validation', component: { title: 'Example OS grid reference', + shortDescription: 'Grid reference', name: 'myComponent', type: ComponentType.OsGridRefField, options: {} @@ -295,7 +308,7 @@ describe('OsGridRefField', () => { value: getFormData('TQ12345'), errors: expect.arrayContaining([ expect.objectContaining({ - text: 'Enter a valid OS grid reference for Example OS grid reference like TQ123456' + text: 'Enter a valid OS grid reference for grid reference like TQ123456' }) ]) } @@ -306,7 +319,7 @@ describe('OsGridRefField', () => { value: getFormData('AA1234567'), errors: expect.arrayContaining([ expect.objectContaining({ - text: 'Enter a valid OS grid reference for Example OS grid reference like TQ123456' + text: 'Enter a valid OS grid reference for grid reference like TQ123456' }) ]) } @@ -317,7 +330,7 @@ describe('OsGridRefField', () => { value: getFormData('TQABCDEF'), errors: expect.arrayContaining([ expect.objectContaining({ - text: 'Enter a valid OS grid reference for Example OS grid reference like TQ123456' + text: 'Enter a valid OS grid reference for grid reference like TQ123456' }) ]) } diff --git a/src/server/plugins/engine/components/OsGridRefField.ts b/src/server/plugins/engine/components/OsGridRefField.ts index 5a27e8147..5902a15ea 100644 --- a/src/server/plugins/engine/components/OsGridRefField.ts +++ b/src/server/plugins/engine/components/OsGridRefField.ts @@ -1,4 +1,5 @@ import { type OsGridRefFieldComponent } from '@defra/forms-model' +import lowerFirst from 'lodash/lowerFirst.js' import { LocationFieldBase } from '~/src/server/plugins/engine/components/LocationFieldBase.js' @@ -6,15 +7,18 @@ export class OsGridRefField extends LocationFieldBase { declare options: OsGridRefFieldComponent['options'] protected getValidationConfig() { - // Regex for OS grid references and parcel IDs + // Regex for OS national grid references (NGR) // Validates specific valid OS grid letter combinations with: - // - 2 letters & 6 digits (e.g., SD865005 or SD 865 005) + // - 2 letters & 6 digits in 2 blocks of 3 e.g. ST 678 678 + // - 2 letters & 8 digits in 2 blocks of 4 e.g. ST 6789 6789 + // - 2 letters & 10 digits in 2 blocks of 5 e.g. SO 12345 12345 + // Optional spaces between each block const pattern = - /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?(([0-9]{3})\s?([0-9]{3}))$/ + /^((([sS]|[nN])[a-hA-Hj-zJ-Z])|(([tT]|[oO])[abfglmqrvwABFGLMQRVW])|([hH][l-zL-Z])|([jJ][lmqrvwLMQRVW]))\s?(([0-9]{3})\s?([0-9]{3})|([0-9]{4})\s?([0-9]{4})|([0-9]{5})\s?([0-9]{5}))$/ return { pattern, - patternErrorMessage: `Enter a valid OS grid reference for ${this.title} like TQ123456` + patternErrorMessage: `Enter a valid OS grid reference for ${lowerFirst(this.label)} like TQ123456` } } diff --git a/src/server/plugins/engine/components/types.ts b/src/server/plugins/engine/components/types.ts index 0d8e37266..0f369d483 100644 --- a/src/server/plugins/engine/components/types.ts +++ b/src/server/plugins/engine/components/types.ts @@ -64,6 +64,9 @@ export interface DateInputItem { // but not by date fields. This interface is reused by both component types. prefix?: ComponentText suffix?: ComponentText + errorMessage?: { + text: string + } condition?: undefined } diff --git a/src/server/plugins/engine/views/components/_location-field-base.html b/src/server/plugins/engine/views/components/_location-field-base.html index df6dbfffc..742a9b448 100644 --- a/src/server/plugins/engine/views/components/_location-field-base.html +++ b/src/server/plugins/engine/views/components/_location-field-base.html @@ -12,22 +12,22 @@ }) }} {% endif %} -