Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 3 additions & 3 deletions website/modules/asset/ui/src/js/formValidator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
},
],
});
Expand Down
16 changes: 13 additions & 3 deletions website/modules/asset/ui/src/js/phoneNumberValidator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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 () => {
Expand Down
50 changes: 21 additions & 29 deletions website/modules/asset/ui/src/js/validationSchemas.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const { formatPhoneNumber } = require('./phoneFormat');
const {
STANDARD_FORM_FIELD_NAMES,
} = require('../../../../@apostrophecms/shared-constants/ui/src/index');
Expand Down Expand Up @@ -33,38 +34,29 @@ const fieldSpecificSchemas = {

[STANDARD_FORM_FIELD_NAMES.PHONE_NUMBER]: yup
.string()
.trim()
.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, '');
.test('phone-format', 'Enter a valid phone number', (value, context) => {
if (/[A-Za-z]/u.test(value)) return false;
Comment thread
VitalyyP marked this conversation as resolved.

// 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);
}
// 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',
});
}

// Otherwise check both patterns
return internationalPattern.test(value) || localPattern.test(value);
},
),
const formatted = formatPhoneNumber(value);
return Boolean(formatted);
}),

'g-recaptcha-response': yup
.string()
Expand Down
8 changes: 4 additions & 4 deletions website/modules/asset/ui/src/js/validationSchemas.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
);
});

Expand All @@ -120,15 +120,15 @@ describe('Phone Number Schema', () => {
);
});

test('rejects invalid format', async () => {
test('rejects phone number with only letters', async () => {
await expect(schema.validate('abc')).rejects.toThrow(
'Enter a valid phone number (e.g., +1 (234) 567-8900)',
'Enter a valid phone number',
);
});

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',
);
});
});
Expand Down
Loading