From e62a98b29f93698bad6de40a483fd06ab1ed0314 Mon Sep 17 00:00:00 2001 From: Vitalii Pikozh Date: Fri, 8 Aug 2025 19:07:16 +0300 Subject: [PATCH 1/3] use formatPhoneNumber function for validation, set min --- .../asset/ui/src/js/formValidator.test.js | 6 +-- .../ui/src/js/phoneNumberValidator.test.js | 16 ++++++-- .../asset/ui/src/js/validationSchemas.js | 41 +++++-------------- .../asset/ui/src/js/validationSchemas.test.js | 6 +-- 4 files changed, 29 insertions(+), 40 deletions(-) diff --git a/website/modules/asset/ui/src/js/formValidator.test.js b/website/modules/asset/ui/src/js/formValidator.test.js index c021a196..c0bb8413 100644 --- a/website/modules/asset/ui/src/js/formValidator.test.js +++ b/website/modules/asset/ui/src/js/formValidator.test.js @@ -14,7 +14,7 @@ const TEST_CONSTANTS = { EMAIL_INVALID: 'Enter a valid email address', EMAIL_DOMAIN_INVALID: 'Check the domain part of the email', PHONE_REQUIRED: 'Phone number is required', - PHONE_INVALID: 'Enter a valid phone number (e.g., +1 (234) 567-8900)', + PHONE_INVALID: 'Enter a valid phone number', TEXT_TOO_LONG: 'Maximum 50 characters', TEXT_TOO_SHORT: 'Minimum 2 characters', TEXTAREA_TOO_LONG: 'Maximum 200 characters', @@ -199,12 +199,12 @@ const testPhoneNumber = () => { description: 'rejects too short phone number', value: TEST_CONSTANTS.INVALID_SAMPLES.PHONE_SHORT, - message: TEST_CONSTANTS.MESSAGES.PHONE_INVALID, + message: 'Phone number is too short', }, { description: 'rejects invalid international format', value: TEST_CONSTANTS.INVALID_SAMPLES.PHONE_INVALID, - message: TEST_CONSTANTS.MESSAGES.PHONE_INVALID, + message: 'Phone number is too short', }, ], }); diff --git a/website/modules/asset/ui/src/js/phoneNumberValidator.test.js b/website/modules/asset/ui/src/js/phoneNumberValidator.test.js index e300751c..9c1a8014 100644 --- a/website/modules/asset/ui/src/js/phoneNumberValidator.test.js +++ b/website/modules/asset/ui/src/js/phoneNumberValidator.test.js @@ -5,7 +5,7 @@ const { describe('Phone Number Validator', () => { let phoneInput = null; - const ERROR_MESSAGE = 'Enter a valid phone number (e.g., +1 (234) 567-8900)'; + const ERROR_MESSAGE = 'Phone number is too short'; beforeEach(() => { phoneInput = document.createElement('input'); @@ -33,11 +33,21 @@ describe('Phone Number Validator', () => { }); it('rejects invalid international format', async () => { - await expectInvalidPhone('+123456789'); + phoneInput.value = '+123'; + const result = await validateField(phoneInput); + expect(result).toEqual({ + isValid: false, + message: 'Phone number is too short', + }); }); it('rejects phone number with letters', async () => { - await expectInvalidPhone('+1 (234) ABC-1234'); + phoneInput.value = '+1 (234) ABC-1234'; + const result = await validateField(phoneInput); + expect(result).toEqual({ + isValid: false, + message: 'Enter a valid phone number', + }); }); it('accepts valid phone number with country code', async () => { diff --git a/website/modules/asset/ui/src/js/validationSchemas.js b/website/modules/asset/ui/src/js/validationSchemas.js index 480ed2f4..838083fd 100644 --- a/website/modules/asset/ui/src/js/validationSchemas.js +++ b/website/modules/asset/ui/src/js/validationSchemas.js @@ -1,3 +1,4 @@ +const { formatPhoneNumber } = require('./phoneFormat'); const { STANDARD_FORM_FIELD_NAMES, } = require('../../../../@apostrophecms/shared-constants/ui/src/index'); @@ -34,37 +35,15 @@ const fieldSpecificSchemas = { [STANDARD_FORM_FIELD_NAMES.PHONE_NUMBER]: yup .string() .required('Phone number is required') - .max(20, 'Phone number is too long') - .test( - 'phone-format', - 'Enter a valid phone number (e.g., +1 (234) 567-8900)', - (value) => { - if (!value) return false; - - // First check for letters - reject immediately if found - if (/[A-Za-z]/u.test(value)) return false; - - // Remove all non-digit characters except leading + - const digits = value.replace(/\D/gu, ''); - - // Check for minimum length (10 digits typical for phone numbers) - if (digits.length < 10) return false; - - // International format: +1 (234) 567-8900 or +1 234 567 8900 or +1.234.567.8900 - const internationalPattern = - /^\+?\d{1,3}[\s.-]?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/u; - // Local format: (234) 567-8900 or 234 567 8900 - const localPattern = /^\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/u; - - // If it starts with +, it must match international pattern - if (value.startsWith('+')) { - return internationalPattern.test(value); - } - - // Otherwise check both patterns - return internationalPattern.test(value) || localPattern.test(value); - }, - ), + .min(10, 'Phone number is too short') + .max(19, 'Phone number is too long') + .test('phone-format', 'Enter a valid phone number', (value) => { + if (!value) return false; + if (/[A-Za-z]/u.test(value)) return false; + + const formatted = formatPhoneNumber(value); + return Boolean(formatted); + }), 'g-recaptcha-response': yup .string() diff --git a/website/modules/asset/ui/src/js/validationSchemas.test.js b/website/modules/asset/ui/src/js/validationSchemas.test.js index cd6841d8..dcd95d29 100644 --- a/website/modules/asset/ui/src/js/validationSchemas.test.js +++ b/website/modules/asset/ui/src/js/validationSchemas.test.js @@ -109,7 +109,7 @@ describe('Phone Number Schema', () => { test('rejects too short phone number', async () => { await expect(schema.validate('123')).rejects.toThrow( - 'Enter a valid phone number (e.g., +1 (234) 567-8900)', + 'Phone number is too short', ); }); @@ -122,13 +122,13 @@ describe('Phone Number Schema', () => { test('rejects invalid format', async () => { await expect(schema.validate('abc')).rejects.toThrow( - 'Enter a valid phone number (e.g., +1 (234) 567-8900)', + 'Phone number is too short', ); }); test('rejects phone number with letters', async () => { await expect(schema.validate('123-ABC-4567')).rejects.toThrow( - 'Enter a valid phone number (e.g., +1 (234) 567-8900)', + 'Enter a valid phone number', ); }); }); From 4499a272b0d7fb93c92756389a1581f00d9fca0b Mon Sep 17 00:00:00 2001 From: Vitalii Pikozh Date: Mon, 11 Aug 2025 13:46:31 +0300 Subject: [PATCH 2/3] fix --- .../asset/ui/src/js/validationSchemas.js | 20 ++++++++++++++++--- .../asset/ui/src/js/validationSchemas.test.js | 4 ++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/website/modules/asset/ui/src/js/validationSchemas.js b/website/modules/asset/ui/src/js/validationSchemas.js index 838083fd..9b2fdf01 100644 --- a/website/modules/asset/ui/src/js/validationSchemas.js +++ b/website/modules/asset/ui/src/js/validationSchemas.js @@ -34,13 +34,27 @@ const fieldSpecificSchemas = { [STANDARD_FORM_FIELD_NAMES.PHONE_NUMBER]: yup .string() + .trim() .required('Phone number is required') - .min(10, 'Phone number is too short') - .max(19, 'Phone number is too long') - .test('phone-format', 'Enter a valid phone number', (value) => { + .test('phone-format', 'Enter a valid phone number', (value, context) => { if (!value) return false; if (/[A-Za-z]/u.test(value)) return false; + // Check digit length after removing non-digit characters + const digits = value.replace(/\D/gu, ''); + if (digits.length < 10) { + return context.createError({ + path: context.path, + message: 'Phone number is too short', + }); + } + if (digits.length > 15) { + return context.createError({ + path: context.path, + message: 'Phone number is too long', + }); + } + const formatted = formatPhoneNumber(value); return Boolean(formatted); }), diff --git a/website/modules/asset/ui/src/js/validationSchemas.test.js b/website/modules/asset/ui/src/js/validationSchemas.test.js index dcd95d29..870cdb68 100644 --- a/website/modules/asset/ui/src/js/validationSchemas.test.js +++ b/website/modules/asset/ui/src/js/validationSchemas.test.js @@ -120,9 +120,9 @@ describe('Phone Number Schema', () => { ); }); - test('rejects invalid format', async () => { + test('rejects phone number with only letters', async () => { await expect(schema.validate('abc')).rejects.toThrow( - 'Phone number is too short', + 'Enter a valid phone number', ); }); From 55c42f467d6e60c735239f799091dda0595f7cb6 Mon Sep 17 00:00:00 2001 From: Vitalii Pikozh Date: Mon, 11 Aug 2025 15:03:45 +0300 Subject: [PATCH 3/3] get rid of an unnecessary condition --- website/modules/asset/ui/src/js/validationSchemas.js | 1 - 1 file changed, 1 deletion(-) diff --git a/website/modules/asset/ui/src/js/validationSchemas.js b/website/modules/asset/ui/src/js/validationSchemas.js index 9b2fdf01..52d2453f 100644 --- a/website/modules/asset/ui/src/js/validationSchemas.js +++ b/website/modules/asset/ui/src/js/validationSchemas.js @@ -37,7 +37,6 @@ const fieldSpecificSchemas = { .trim() .required('Phone number is required') .test('phone-format', 'Enter a valid phone number', (value, context) => { - if (!value) return false; if (/[A-Za-z]/u.test(value)) return false; // Check digit length after removing non-digit characters