diff --git a/model/src/components/types.ts b/model/src/components/types.ts index 329765230d..1dc0f2e06c 100644 --- a/model/src/components/types.ts +++ b/model/src/components/types.ts @@ -190,6 +190,7 @@ export interface TelephoneNumberFieldComponent extends TextFieldBase { type: "TelephoneNumberField"; options: TextFieldBase["options"] & { customValidationMessage?: string; + isInternational?: boolean; }; } diff --git a/runner/package.json b/runner/package.json index 559225cfc9..11821897ca 100644 --- a/runner/package.json +++ b/runner/package.json @@ -49,6 +49,7 @@ "@hapi/vision": "^7.0.3", "@hapi/wreck": "^18.0.1", "@hapi/yar": "^11.0.1", + "@types/google-libphonenumber": "^7.4.30", "accept-language-parser": "1.5.0", "accessible-autocomplete": "^2.0.2", "atob": "^2.1.2", @@ -60,6 +61,7 @@ "config": "^3.3.7", "dotenv": "8.2.0", "expr-eval": "^2.0.2", + "google-libphonenumber": "^3.2.34", "govuk-frontend": "^4.8.0", "hapi-pino": "8.0.0", "hapi-pulse": "3.0.0", diff --git a/runner/src/server/plugins/engine/components/TelephoneNumberField.ts b/runner/src/server/plugins/engine/components/TelephoneNumberField.ts index 9d05afa513..59fe21b60c 100644 --- a/runner/src/server/plugins/engine/components/TelephoneNumberField.ts +++ b/runner/src/server/plugins/engine/components/TelephoneNumberField.ts @@ -2,7 +2,7 @@ import { TelephoneNumberFieldComponent } from "@xgovformbuilder/model"; import { FormComponent } from "./FormComponent"; import { FormModel } from "../models"; -import { addClassOptionIfNone } from "./helpers"; +import { addClassOptionIfNone, internationalPhoneValidator } from "./helpers"; import { FormData, FormSubmissionErrors } from "../types"; import joi, { Schema } from "joi"; @@ -32,6 +32,9 @@ export class TelephoneNumberField extends FormComponent { componentSchema = componentSchema.min(schema.min); } + if (options.isInternational) { + componentSchema = componentSchema.custom(internationalPhoneValidator); + } this.schema = componentSchema; addClassOptionIfNone(this.options, "govuk-input--width-10"); diff --git a/runner/src/server/plugins/engine/components/helpers.ts b/runner/src/server/plugins/engine/components/helpers.ts index 77b97c0566..a268ba8e04 100644 --- a/runner/src/server/plugins/engine/components/helpers.ts +++ b/runner/src/server/plugins/engine/components/helpers.ts @@ -1,5 +1,8 @@ import joi from "joi"; import { add, startOfToday, sub } from "date-fns"; +import { PhoneNumberFormat, PhoneNumberUtil } from "google-libphonenumber"; + +const phoneUtil = PhoneNumberUtil.getInstance(); /** * FIXME:- this code is bonkers. buildFormSchema and buildState schema are duplicates. @@ -117,3 +120,11 @@ export function getCustomDateValidator( return value; }; } + +export function internationalPhoneValidator( + value: string, + _helpers: joi.CustomHelpers +) { + const phone = phoneUtil.parseAndKeepRawInput(value); + return phoneUtil.format(phone, PhoneNumberFormat.INTERNATIONAL); +} diff --git a/yarn.lock b/yarn.lock index cf58c7bed3..c40aef7d41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4031,6 +4031,13 @@ __metadata: languageName: node linkType: hard +"@types/google-libphonenumber@npm:^7.4.30": + version: 7.4.30 + resolution: "@types/google-libphonenumber@npm:7.4.30" + checksum: 09270ed030076a0e69965ad5bad564e672a110e1e83c9092f6d264c3e0355921631521cb9afd022018a51cddfd19ba52d0421f4682d7b68b836dbb52537320de + languageName: node + linkType: hard + "@types/graceful-fs@npm:^4.1.2, @types/graceful-fs@npm:^4.1.3": version: 4.1.9 resolution: "@types/graceful-fs@npm:4.1.9" @@ -5127,6 +5134,7 @@ __metadata: "@hapi/wreck": ^18.0.1 "@hapi/yar": ^11.0.1 "@oclif/core": ^1.19.0 + "@types/google-libphonenumber": ^7.4.30 "@types/hapi": ^18.0.7 "@types/hapi__yar": ^10.1.1 "@types/hoek": ^4.1.4 @@ -5161,6 +5169,7 @@ __metadata: expr-eval: ^2.0.2 flat: 5.0.2 form-data: ^4.0.0 + google-libphonenumber: ^3.2.34 govuk-frontend: ^4.8.0 hapi-pino: 8.0.0 hapi-pulse: 3.0.0 @@ -11426,6 +11435,13 @@ __metadata: languageName: node linkType: hard +"google-libphonenumber@npm:^3.2.34": + version: 3.2.34 + resolution: "google-libphonenumber@npm:3.2.34" + checksum: a14579bb8d4934dc6b9cfb33f818375ccdc67be12f13f842a4c16d7c3bd8ef9f2aacc30d368770f33a97ba8674e23b318cb59f26616c7fa2ce60fae52b2f6ebf + languageName: node + linkType: hard + "gopd@npm:^1.0.1": version: 1.0.1 resolution: "gopd@npm:1.0.1"