diff --git a/packages/storybook/stories/va-telephone.stories.jsx b/packages/storybook/stories/va-telephone.stories.jsx
index 309554c88..c652cc761 100644
--- a/packages/storybook/stories/va-telephone.stories.jsx
+++ b/packages/storybook/stories/va-telephone.stories.jsx
@@ -60,6 +60,7 @@ const Template = ({
extension,
'not-clickable': notClickable,
international,
+ 'country-code': countryCode,
vanity,
tty,
sms,
@@ -67,14 +68,13 @@ const Template = ({
}) => {
return (
- {messageAriaDescribedBy && (
-
Main number to facility
- )}
+ {messageAriaDescribedBy &&
Main number to facility }
{
await axeCheck(page);
});
+ it('passes an axe check for a phone number with a country code', async () => {
+ const page = await newE2EPage();
+ await page.setContent(
+ '',
+ );
+
+ await axeCheck(page);
+ });
+
it('ignores non-digits in the contact prop', async () => {
const page = await newE2EPage();
- await page.setContent('');
+ await page.setContent(
+ '',
+ );
const link = await page.find('va-telephone >>> a');
expect(link.getAttribute('href')).toEqual('tel:+18779551234');
@@ -118,6 +129,17 @@ describe('va-telephone', () => {
expect(link.innerText).toEqual('877-955-1234, ext. 123');
});
+ it('handles a phone number with a country code', async () => {
+ const page = await newE2EPage();
+ await page.setContent(
+ '',
+ );
+
+ const link = await page.find('va-telephone >>> a');
+ expect(link.getAttribute('href')).toEqual('tel:+630285558888');
+ expect(link.innerText).toEqual('+63 (02) 8555 8888');
+ });
+
it('handles a 3 digit contact prop', async () => {
const page = await newE2EPage();
await page.setContent('');
diff --git a/packages/web-components/src/components/va-telephone/test/va-telephone.spec.tsx b/packages/web-components/src/components/va-telephone/test/va-telephone.spec.tsx
index b1a77d46b..b557bc116 100644
--- a/packages/web-components/src/components/va-telephone/test/va-telephone.spec.tsx
+++ b/packages/web-components/src/components/va-telephone/test/va-telephone.spec.tsx
@@ -2,57 +2,131 @@ import { VaTelephone } from '../va-telephone';
describe('formatPhoneNumber', () => {
const contact = '8885551234';
+ const countryCode = '63';
+ const intlContact = '(02) 8555 8888';
const N11 = '911';
const extension = '123';
const vanity = 'ABCD';
it('formats a contact number with no extension', () => {
- expect(VaTelephone.formatPhoneNumber(contact, null, null, null)).toBe('888-555-1234');
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact,
+ }),
+ ).toBe('888-555-1234');
});
it('formats a contact number with extension', () => {
- expect(VaTelephone.formatPhoneNumber(contact, extension, null, null)).toBe(
- '888-555-1234, ext. 123',
- );
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact,
+ extension,
+ }),
+ ).toBe('888-555-1234, ext. 123');
});
it('formats a 3 digit contact number', () => {
- expect(VaTelephone.formatPhoneNumber(N11, null, null, null)).toBe('911');
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact: N11,
+ }),
+ ).toBe('911');
});
it('does not use extension for 3 digit contact', () => {
- expect(VaTelephone.formatPhoneNumber(N11, extension, null, null)).toBe('911');
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact: N11,
+ extension,
+ }),
+ ).toBe('911');
});
it('does not use international formatting for 3 digit contact', () => {
- expect(VaTelephone.formatPhoneNumber(N11, extension, true, null)).toBe('911');
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact: N11,
+ extension,
+ international: true,
+ }),
+ ).toBe('911');
});
it('formats a contact number with vanity prop', () => {
- expect(VaTelephone.formatPhoneNumber(contact, null, null, vanity)).toBe('888-555-ABCD (1234)');
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact,
+ vanity,
+ }),
+ ).toBe('888-555-ABCD (1234)');
});
it('formats a TTY number', () => {
- expect(VaTelephone.formatPhoneNumber(N11, null, null, null, true)).toBe('TTY: 911');
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact: N11,
+ tty: true,
+ }),
+ ).toBe('TTY: 911');
+ });
+
+ it('formats a contact number with a country code', () => {
+ expect(
+ VaTelephone.formatPhoneNumber({
+ contact: intlContact,
+ countryCode,
+ }),
+ ).toBe('+63 (02) 8555 8888');
});
});
describe('createHref', () => {
const contact = '8885551234';
+ const countryCode = '63';
+ const intlContact = '(02) 8555 8888';
const contactSms = '123456';
const n11 = '911';
const extension = '123';
+
it('creates a tel link for a phone number', () => {
- expect(VaTelephone.createHref(contact, null, null)).toBe('tel:+18885551234');
+ expect(
+ VaTelephone.createHref({
+ contact,
+ }),
+ ).toBe('tel:+18885551234');
});
+
it('creates a tel link for a phone number with extension', () => {
- expect(VaTelephone.createHref(contact, extension, null)).toBe(
- 'tel:+18885551234,123',
- );
+ expect(
+ VaTelephone.createHref({
+ contact,
+ extension,
+ }),
+ ).toBe('tel:+18885551234,123');
});
+
+ it('creates a tel link for a phone number with a country code', () => {
+ expect(
+ VaTelephone.createHref({
+ contact: intlContact,
+ countryCode,
+ }),
+ ).toBe('tel:+630285558888');
+ });
+
it('creates a tel link for an N11 number', () => {
- expect(VaTelephone.createHref(n11, null, null)).toBe('tel:911');
+ expect(
+ VaTelephone.createHref({
+ contact: n11,
+ }),
+ ).toBe('tel:911');
});
+
it('creates an sms link for an SMS number', () => {
- expect(VaTelephone.createHref(contactSms, null, true)).toBe('sms:123456');
+ expect(
+ VaTelephone.createHref({
+ contact: contactSms,
+ sms: true,
+ }),
+ ).toBe('sms:123456');
});
});
\ No newline at end of file
diff --git a/packages/web-components/src/components/va-telephone/va-telephone.tsx b/packages/web-components/src/components/va-telephone/va-telephone.tsx
index 709eaaf80..0118aab2b 100644
--- a/packages/web-components/src/components/va-telephone/va-telephone.tsx
+++ b/packages/web-components/src/components/va-telephone/va-telephone.tsx
@@ -41,6 +41,11 @@ export class VaTelephone {
*/
@Prop() international?: boolean = false;
+ /**
+ * Prepends the country code to the given contact number. Do NOT include the '+'
+ */
+ @Prop() countryCode?: string;
+
/**
* Indicates if this is a number meant to be called
* from a teletypewriter for deaf users.
@@ -75,11 +80,11 @@ export class VaTelephone {
})
componentLibraryAnalytics: EventEmitter;
- static cleanContact(contact: string) :string {
+ static cleanContact(contact: string): string {
return (contact || '').replace(/[^\d]/g, '');
}
- static splitContact(contact: string) :string[] {
+ static splitContact(contact: string): string[] {
const cleanedContact = VaTelephone.cleanContact(contact);
if (cleanedContact.length === 10) {
// const regex = /(?\d{3})(?\d{3})(?\d{4})/g;
@@ -99,17 +104,27 @@ export class VaTelephone {
* Format telephone number for display.
* `international` and `extension` args only work on 10 digit contacts
*/
- static formatPhoneNumber(
- num: string,
- extension: string,
- international: boolean = false,
- vanity: string,
- tty: boolean = false,
- ): string {
- const splitNumber = VaTelephone.splitContact(num);
+ /* eslint-disable i18next/no-literal-string */
+ static formatPhoneNumber({
+ contact: num,
+ extension,
+ international = false,
+ countryCode,
+ vanity,
+ tty = false,
+ }: {
+ contact: string;
+ extension?: string;
+ international?: boolean;
+ countryCode?: string;
+ vanity?: string;
+ tty?: boolean;
+ }): string {
+ const splitNumber = countryCode ? [num] : VaTelephone.splitContact(num);
let formattedNum = splitNumber.join('');
- if (formattedNum.length === 10) {
- const [ area, local, last4 ] = splitNumber;
+
+ if (formattedNum.length === 10 && !countryCode) {
+ const [area, local, last4] = splitNumber;
formattedNum = `${area}-${local}-${last4}`;
if (international) formattedNum = `+1-${formattedNum}`;
if (extension) formattedNum = `${formattedNum}, ext. ${extension}`;
@@ -117,13 +132,29 @@ export class VaTelephone {
formattedNum = `${area}-${local}-${vanity} (${last4})`;
}
}
+
+ if (countryCode) {
+ formattedNum = `+${countryCode} ${formattedNum}`;
+ }
+
if (tty) {
formattedNum = `TTY: ${formattedNum}`;
}
+
return formattedNum;
}
- static createHref(contact: string, extension: string, sms: boolean): string {
+ static createHref({
+ contact,
+ extension,
+ sms,
+ countryCode,
+ }: {
+ contact: string;
+ extension?: string;
+ sms?: boolean;
+ countryCode?: string;
+ }): string {
const cleanedContact = VaTelephone.cleanContact(contact);
const isN11 = cleanedContact.length === 3;
// extension format ";ext=" from RFC3966 https://tools.ietf.org/html/rfc3966#page-5
@@ -134,11 +165,15 @@ export class VaTelephone {
href = `sms:${cleanedContact}`;
} else if (isN11) {
href = `tel:${cleanedContact}`;
+ } else if (countryCode) {
+ href = `tel:+${countryCode}${cleanedContact}`;
} else {
+ // RFC3966 (https://www.rfc-editor.org/rfc/rfc3966#section-5.1.5) calls for the inclusion of country codes whenever possible, so we add the +1 unless we know there's a different country code (above)
href = `tel:+1${cleanedContact}`;
}
return `${href}${extension ? `,${extension}` : ''}`;
}
+ /* eslint-enable i18next/no-literal-string */
private handleClick(): void {
this.componentLibraryAnalytics.emit({
@@ -152,37 +187,50 @@ export class VaTelephone {
}
render() {
- const {
- contact,
- extension,
- notClickable,
- international,
- tty,
- vanity,
- sms,
- messageAriaDescribedby
- } = this;
- const formattedNumber = VaTelephone.formatPhoneNumber(
+ const {
contact,
extension,
+ notClickable,
international,
+ countryCode,
+ tty,
vanity,
- tty
- );
+ sms,
+ messageAriaDescribedby,
+ } = this;
+ const formattedNumber = VaTelephone.formatPhoneNumber({
+ contact: contact,
+ extension,
+ international,
+ countryCode,
+ vanity,
+ tty,
+ });
+ const href = VaTelephone.createHref({
+ contact,
+ extension,
+ sms,
+ countryCode,
+ });
// Null so we don't add the attribute if we have an empty string
- const ariaDescribedbyIds = messageAriaDescribedby ? 'number-description' : null;
+ const ariaDescribedbyIds = messageAriaDescribedby
+ ? // eslint-disable-next-line i18next/no-literal-string
+ 'number-description'
+ : null;
- return (
+ return (
{notClickable ? (
- {formattedNumber}
+
+ {formattedNumber}
+
) : (
{formattedNumber}