Skip to content

Commit 708c52e

Browse files
Allow multiple countries with same country code (#2586)
Co-authored-by: Connor Bär <[email protected]> Co-authored-by: Connor Bär <[email protected]>
1 parent 7fce1de commit 708c52e

File tree

6 files changed

+57
-32
lines changed

6 files changed

+57
-32
lines changed

.changeset/two-horses-fold.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sumup/circuit-ui': minor
3+
---
4+
5+
Use the country code instead of the phone prefix as the value of the PhoneNumberInput component's country code select. This is an implementation detail, but might require changes to unit tests that query the country code select.

packages/circuit-ui/components/PhoneNumberInput/PhoneNumberInput.spec.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ import {
2525
} from './PhoneNumberInput.js';
2626

2727
const countryCodeMap: { [key: string]: string } = {
28-
'+1': 'US',
29-
'+49': 'DE',
28+
CA: '+1',
29+
US: '+1',
30+
DE: '+49',
3031
};
3132

3233
const defaultProps = {
@@ -35,8 +36,8 @@ const defaultProps = {
3536
label: 'Country code',
3637
defaultValue: '+1',
3738
options: Object.keys(countryCodeMap).map((key) => ({
38-
country: countryCodeMap[key],
39-
code: key,
39+
country: key,
40+
code: countryCodeMap[key],
4041
})),
4142
},
4243
subscriberNumber: {
@@ -85,7 +86,7 @@ describe('PhoneNumberInput', () => {
8586
};
8687
render(<PhoneNumberInput {...props} />);
8788
const select = screen.getByRole('combobox');
88-
await userEvent.selectOptions(select, '+49');
89+
await userEvent.selectOptions(select, 'DE');
8990
expect(onChange).toHaveBeenCalledOnce();
9091
});
9192

@@ -100,7 +101,7 @@ describe('PhoneNumberInput', () => {
100101
};
101102
render(<PhoneNumberInput {...props} />);
102103
const select = screen.getByRole('combobox');
103-
await userEvent.selectOptions(select, '+49');
104+
await userEvent.selectOptions(select, 'DE');
104105
expect(onChange).toHaveBeenCalledOnce();
105106
});
106107

packages/circuit-ui/components/PhoneNumberInput/PhoneNumberInput.stories.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { FlagDe, FlagUs, type IconComponentType } from '@sumup/icons';
16+
import { FlagCa, FlagDe, FlagUs, type IconComponentType } from '@sumup/icons';
1717
import { useState } from 'react';
1818
import { action } from '@storybook/addon-actions';
1919

@@ -33,13 +33,15 @@ export default {
3333
};
3434

3535
const flagIconMap: { [key: string]: IconComponentType<'16'> } = {
36-
DE: FlagDe,
36+
CA: FlagCa,
3737
US: FlagUs,
38+
DE: FlagDe,
3839
};
3940

4041
const countryCodeMap: { [key: string]: string } = {
41-
'+1': 'US',
42-
'+49': 'DE',
42+
CA: '+1',
43+
US: '+1',
44+
DE: '+49',
4345
};
4446

4547
export const Base = (args: PhoneNumberInputProps) => (
@@ -52,8 +54,8 @@ Base.args = {
5254
label: 'Country code',
5355
defaultValue: '+1',
5456
options: Object.keys(countryCodeMap).map((key) => ({
55-
country: countryCodeMap[key],
56-
code: key,
57+
country: key,
58+
code: countryCodeMap[key],
5759
})),
5860
},
5961
subscriberNumber: {
@@ -125,14 +127,14 @@ Disabled.args = {
125127
};
126128

127129
export const WithPrefix = (args: PhoneNumberInputProps) => {
128-
const [selectedCountry, setSelectedCountry] = useState('US');
130+
const [selectedCountry, setSelectedCountry] = useState('CA');
129131
return (
130132
<PhoneNumberInput
131133
{...args}
132134
countryCode={{
133135
...args.countryCode,
134136
onChange: (event) => {
135-
setSelectedCountry(countryCodeMap[event.target.value]);
137+
setSelectedCountry(event.target.value);
136138
},
137139
renderPrefix: (props) => {
138140
const Icon = flagIconMap[selectedCountry];

packages/circuit-ui/components/PhoneNumberInput/PhoneNumberInput.tsx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,20 @@ export const PhoneNumberInput = forwardRef<
240240
) {
241241
return;
242242
}
243+
244+
const selectedCountry = countryCodeRef?.current?.value;
245+
if (!selectedCountry) {
246+
return;
247+
}
248+
const code = countryCode.options.find(
249+
({ country }) => country === selectedCountry,
250+
)?.code;
251+
252+
if (!code) {
253+
return;
254+
}
243255
const phoneNumber = normalizePhoneNumber(
244-
countryCodeRef.current.value,
256+
code,
245257
subscriberNumberRef.current.value,
246258
);
247259
onChange(phoneNumber);
@@ -273,21 +285,20 @@ export const PhoneNumberInput = forwardRef<
273285
return;
274286
}
275287

276-
const pastedCountryCode = countryCode.options
277-
.map((option) => option.code)
288+
const pastedOption = countryCode.options
278289
// Match longer, more specific country codes first
279-
.sort((a, b) => b.length - a.length)
280-
.find((code) => pastedText.startsWith(code));
290+
.sort((a, b) => b.code.length - a.code.length)
291+
.find(({ code }) => pastedText.startsWith(code));
281292

282-
if (!pastedCountryCode) {
293+
if (!pastedOption) {
283294
return;
284295
}
285296

286297
event.preventDefault();
287298

288-
const pastedSubscriberNumber = pastedText.split(pastedCountryCode)[1];
299+
const pastedSubscriberNumber = pastedText.split(pastedOption.code)[1];
289300

290-
countryCodeRef.current.value = pastedCountryCode;
301+
countryCodeRef.current.value = pastedOption.country;
291302

292303
// React overwrites the input.value setter. In order to be able to trigger
293304
// a 'change' event on the input, we need to use the native setter.

packages/circuit-ui/components/PhoneNumberInput/PhoneNumberInputService.spec.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,28 @@ describe('PhoneNumberInputService', () => {
5252
});
5353

5454
describe('mapCountryCodeOptions', () => {
55-
it('should use the country code as the option value', () => {
55+
it('should use the country as the option value', () => {
5656
const options = [
57+
{ country: 'CA', code: '+1' },
5758
{ country: 'US', code: '+1' },
5859
{ country: 'DE', code: '+49' },
5960
];
6061
const actual = mapCountryCodeOptions(options);
61-
expect(actual[0].value).toBe('+49');
62-
expect(actual[1].value).toBe('+1');
62+
expect(actual[0].value).toBe('CA');
63+
expect(actual[1].value).toBe('DE');
64+
expect(actual[2].value).toBe('US');
6365
});
6466

6567
it('should use the country name and code as the option label', () => {
6668
const options = [
69+
{ country: 'CA', code: '+1' },
6770
{ country: 'US', code: '+1' },
6871
{ country: 'DE', code: '+49' },
6972
];
7073
const actual = mapCountryCodeOptions(options);
71-
expect(actual[0].label).toBe('Germany (+49)');
72-
expect(actual[1].label).toBe('United States (+1)');
74+
expect(actual[0].label).toBe('Canada (+1)');
75+
expect(actual[1].label).toBe('Germany (+49)');
76+
expect(actual[2].label).toBe('United States (+1)');
7377
});
7478

7579
it('should omit the country name when it is not available', () => {
@@ -80,22 +84,24 @@ describe('PhoneNumberInputService', () => {
8084

8185
it('should sort the options alphabetically', () => {
8286
const options = [
87+
{ country: 'CA', code: '+1' },
8388
{ country: 'US', code: '+1' },
8489
{ country: 'DE', code: '+49' },
8590
];
8691
const actual = mapCountryCodeOptions(options);
87-
expect(actual[0].label).toBe('Germany (+49)');
88-
expect(actual[1].label).toBe('United States (+1)');
92+
expect(actual[0].label).toBe('Canada (+1)');
93+
expect(actual[1].label).toBe('Germany (+49)');
94+
expect(actual[2].label).toBe('United States (+1)');
8995
});
9096

9197
it('should use the locale as the default country code', () => {
9298
const options = [
99+
{ country: 'CA', code: '+1' },
93100
{ country: 'US', code: '+1' },
94101
{ country: 'DE', code: '+49' },
95-
{ country: 'CA', code: '+1' },
96102
];
97103
const actual = mapCountryCodeOptions(options, 'DE');
98-
expect(actual[0].value).toBe('+49');
104+
expect(actual[0].value).toBe('DE');
99105
});
100106
});
101107
});

packages/circuit-ui/components/PhoneNumberInput/PhoneNumberInputService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function mapCountryCodeOptions(
4949
const countryName = displayName.of(country);
5050
return {
5151
label: countryName ? `${countryName} (${code})` : code,
52-
value: code,
52+
value: country,
5353
};
5454
})
5555
.sort((a, b) => a.label.localeCompare(b.label));

0 commit comments

Comments
 (0)