Skip to content

Commit 5fa6051

Browse files
committed
Merge branch 'main' into 772-feature/prevent-content-flash
2 parents 4c7f379 + 730bb8e commit 5fa6051

7 files changed

Lines changed: 73 additions & 59 deletions

File tree

website/modules/asset/ui/src/js/formValidator.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const TEST_CONSTANTS = {
1414
EMAIL_INVALID: 'Enter a valid email address',
1515
EMAIL_DOMAIN_INVALID: 'Check the domain part of the email',
1616
PHONE_REQUIRED: 'Phone number is required',
17-
PHONE_INVALID: 'Enter a valid phone number (e.g., +1 (234) 567-8900)',
17+
PHONE_INVALID: 'Enter a valid phone number',
1818
TEXT_TOO_LONG: 'Maximum 50 characters',
1919
TEXT_TOO_SHORT: 'Minimum 2 characters',
2020
TEXTAREA_TOO_LONG: 'Maximum 200 characters',
@@ -199,12 +199,12 @@ const testPhoneNumber = () =>
199199
{
200200
description: 'rejects too short phone number',
201201
value: TEST_CONSTANTS.INVALID_SAMPLES.PHONE_SHORT,
202-
message: TEST_CONSTANTS.MESSAGES.PHONE_INVALID,
202+
message: 'Phone number is too short',
203203
},
204204
{
205205
description: 'rejects invalid international format',
206206
value: TEST_CONSTANTS.INVALID_SAMPLES.PHONE_INVALID,
207-
message: TEST_CONSTANTS.MESSAGES.PHONE_INVALID,
207+
message: 'Phone number is too short',
208208
},
209209
],
210210
});

website/modules/asset/ui/src/js/phoneNumberValidator.test.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const {
55

66
describe('Phone Number Validator', () => {
77
let phoneInput = null;
8-
const ERROR_MESSAGE = 'Enter a valid phone number (e.g., +1 (234) 567-8900)';
8+
const ERROR_MESSAGE = 'Phone number is too short';
99

1010
beforeEach(() => {
1111
phoneInput = document.createElement('input');
@@ -33,11 +33,21 @@ describe('Phone Number Validator', () => {
3333
});
3434

3535
it('rejects invalid international format', async () => {
36-
await expectInvalidPhone('+123456789');
36+
phoneInput.value = '+123';
37+
const result = await validateField(phoneInput);
38+
expect(result).toEqual({
39+
isValid: false,
40+
message: 'Phone number is too short',
41+
});
3742
});
3843

3944
it('rejects phone number with letters', async () => {
40-
await expectInvalidPhone('+1 (234) ABC-1234');
45+
phoneInput.value = '+1 (234) ABC-1234';
46+
const result = await validateField(phoneInput);
47+
expect(result).toEqual({
48+
isValid: false,
49+
message: 'Enter a valid phone number',
50+
});
4151
});
4252

4353
it('accepts valid phone number with country code', async () => {

website/modules/asset/ui/src/js/validationSchemas.js

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const { formatPhoneNumber } = require('./phoneFormat');
12
const {
23
STANDARD_FORM_FIELD_NAMES,
34
} = require('../../../../@apostrophecms/shared-constants/ui/src/index');
@@ -33,38 +34,29 @@ const fieldSpecificSchemas = {
3334

3435
[STANDARD_FORM_FIELD_NAMES.PHONE_NUMBER]: yup
3536
.string()
37+
.trim()
3638
.required('Phone number is required')
37-
.max(20, 'Phone number is too long')
38-
.test(
39-
'phone-format',
40-
'Enter a valid phone number (e.g., +1 (234) 567-8900)',
41-
(value) => {
42-
if (!value) return false;
43-
44-
// First check for letters - reject immediately if found
45-
if (/[A-Za-z]/u.test(value)) return false;
46-
47-
// Remove all non-digit characters except leading +
48-
const digits = value.replace(/\D/gu, '');
39+
.test('phone-format', 'Enter a valid phone number', (value, context) => {
40+
if (/[A-Za-z]/u.test(value)) return false;
4941

50-
// Check for minimum length (10 digits typical for phone numbers)
51-
if (digits.length < 10) return false;
52-
53-
// International format: +1 (234) 567-8900 or +1 234 567 8900 or +1.234.567.8900
54-
const internationalPattern =
55-
/^\+?\d{1,3}[\s.-]?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/u;
56-
// Local format: (234) 567-8900 or 234 567 8900
57-
const localPattern = /^\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/u;
58-
59-
// If it starts with +, it must match international pattern
60-
if (value.startsWith('+')) {
61-
return internationalPattern.test(value);
62-
}
42+
// Check digit length after removing non-digit characters
43+
const digits = value.replace(/\D/gu, '');
44+
if (digits.length < 10) {
45+
return context.createError({
46+
path: context.path,
47+
message: 'Phone number is too short',
48+
});
49+
}
50+
if (digits.length > 15) {
51+
return context.createError({
52+
path: context.path,
53+
message: 'Phone number is too long',
54+
});
55+
}
6356

64-
// Otherwise check both patterns
65-
return internationalPattern.test(value) || localPattern.test(value);
66-
},
67-
),
57+
const formatted = formatPhoneNumber(value);
58+
return Boolean(formatted);
59+
}),
6860

6961
'g-recaptcha-response': yup
7062
.string()

website/modules/asset/ui/src/js/validationSchemas.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe('Phone Number Schema', () => {
109109

110110
test('rejects too short phone number', async () => {
111111
await expect(schema.validate('123')).rejects.toThrow(
112-
'Enter a valid phone number (e.g., +1 (234) 567-8900)',
112+
'Phone number is too short',
113113
);
114114
});
115115

@@ -120,15 +120,15 @@ describe('Phone Number Schema', () => {
120120
);
121121
});
122122

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

129129
test('rejects phone number with letters', async () => {
130130
await expect(schema.validate('123-ABC-4567')).rejects.toThrow(
131-
'Enter a valid phone number (e.g., +1 (234) 567-8900)',
131+
'Enter a valid phone number',
132132
);
133133
});
134134
});

website/modules/asset/ui/src/scss/_carousel.scss

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,16 @@
4444
text-decoration: none;
4545
@include truncate-lines(2);
4646
}
47-
&__wrapper{
47+
&__wrapper {
4848
display: flex;
4949
flex-direction: row;
5050
flex-wrap: wrap;
5151
margin-bottom: 4px;
5252
@include breakpoint-medium {
5353
margin-bottom: 8px;
5454
}
55-
5655
}
57-
&__container{
56+
&__container {
5857
display: flex;
5958
flex-direction: column;
6059
justify-content: center;
@@ -92,16 +91,13 @@
9291
@include truncate-lines(1);
9392
}
9493
&__content {
95-
font-weight: 500;
96-
font-size: 14px;
97-
line-height: 21px;
98-
color: $gray-300;
99-
margin: 0;
100-
@include breakpoint-medium {
101-
@include truncate-lines(8);
102-
}
94+
font-weight: 500;
95+
font-size: 14px;
96+
line-height: 21px;
97+
color: $gray-300;
98+
margin: 0;
10399
}
104-
100+
105101
&__url {
106102
text-decoration: none;
107103
font-weight: 700;

website/modules/asset/ui/src/scss/_testimonials.scss

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,19 @@
7171
}
7272
.sf-person__content {
7373
color: $gray-300;
74-
@include truncate-lines(7);
74+
75+
overflow-x: hidden;
76+
overflow-y: auto;
77+
max-height: 150px;
78+
79+
overflow-wrap: anywhere;
80+
word-break: break-word;
81+
82+
-webkit-overflow-scrolling: touch;
83+
overscroll-behavior: contain;
84+
scrollbar-gutter: stable both-edges;
85+
padding-right: 12px;
86+
7587
@include font-settings(14px, 150%, 400);
7688
}
7789
}
@@ -134,7 +146,6 @@
134146
@include breakpoint-medium {
135147
height: 400px;
136148
.sf-person__content {
137-
@include truncate-lines(10);
138149
@include font-settings(22px, 150%, 400);
139150
}
140151
}

website/modules/case-studies-page/views/show.html

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,18 +168,23 @@ <h2 class="portfolio-title">{{ data.piece.portfolioTitle }}</h2>
168168
<div class="links-area">
169169
{% if data.piece.fullStoryUrl %}
170170
<a
171-
href="{{ data.piece.fullStoryUrl }}"
172-
target="_blank"
173-
rel="noopener noreferrer"
174-
class="full-story_btn"
175-
>Read The Full Story</a
171+
href="{{ data.piece.fullStoryUrl }}"
172+
target="_blank"
173+
rel="noopener noreferrer"
174+
class="full-story_btn"
175+
>Read The Full Story</a
176176
>
177177
{% endif %} {% if data.piece.prodLink %}
178+
{# Remove path/query/fragment #}
179+
{% set urlWithoutProtocol = data.piece.prodLink | replace('https://', '') | replace('http://', '') %}
180+
{% set domainWithOrWithoutWww = urlWithoutProtocol.split('/')[0] %}
181+
{% set cleanDomain = domainWithOrWithoutWww | trim | replace('www.', '') %}
178182
<a
179183
href="{{ data.piece.prodLink }}"
180184
target="_blank"
181185
class="prod-link"
182-
>{{ data.piece.prodLink }}</a
186+
rel="noopener noreferrer"
187+
>{{ cleanDomain }}</a
183188
>
184189
{% endif %}
185190
</div>

0 commit comments

Comments
 (0)