Skip to content
Merged
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
60 changes: 0 additions & 60 deletions src/client/stylesheets/_location-input.scss

This file was deleted.

1 change: 0 additions & 1 deletion src/client/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/client/stylesheets/shared.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions src/server/forms/register-as-a-unicorn-breeder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: ''
Expand All @@ -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'
})
)
})
Expand Down
25 changes: 13 additions & 12 deletions src/server/plugins/engine/components/EastingNorthingField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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',
Expand Down
12 changes: 9 additions & 3 deletions src/server/plugins/engine/components/LatLongField.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: ''
Expand All @@ -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'
})
)
})
Expand Down
13 changes: 7 additions & 6 deletions src/server/plugins/engine/components/LatLongField.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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(
Expand Down
19 changes: 14 additions & 5 deletions src/server/plugins/engine/components/LocationFieldHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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'
}
})
)
})
Expand Down
12 changes: 3 additions & 9 deletions src/server/plugins/engine/components/LocationFieldHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)) {
Expand All @@ -64,7 +57,8 @@ export function getLocationFieldViewModel(
value,
classes,
prefix,
suffix
suffix,
errorMessage
}
})

Expand Down
Loading
Loading