Skip to content

Commit cd55ada

Browse files
authored
[SDK] Feature: Adds defaultCountryCode prop to ConnectButton (#5709)
1 parent 3ec808d commit cd55ada

File tree

9 files changed

+148
-16
lines changed

9 files changed

+148
-16
lines changed

.changeset/fast-items-film.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
"thirdweb": minor
3+
---
4+
5+
Adds a defaultSmsCountryCode configuration option to In-App and Ecosystem Wallets
6+
7+
```ts
8+
createWallet("inApp", {
9+
auth: {
10+
options: [
11+
"email",
12+
"phone",
13+
],
14+
mode: "redirect",
15+
defaultSmsCountryCode: "IN", // Default country code for SMS
16+
},
17+
}),
18+
```
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
import {
3+
fireEvent,
4+
render,
5+
screen,
6+
} from "../../../../../test/src/react-render.js";
7+
import { CountrySelector } from "./CountrySelector.js";
8+
9+
describe("CountrySelector", () => {
10+
it("renders with default country code", () => {
11+
const setCountryCode = vi.fn();
12+
render(
13+
<CountrySelector countryCode="US +1" setCountryCode={setCountryCode} />,
14+
);
15+
16+
const selectElement = screen.getByRole("combobox");
17+
expect(selectElement).toBeTruthy();
18+
expect(selectElement).toHaveValue("US +1");
19+
});
20+
21+
it("changes country code on selection", () => {
22+
const setCountryCode = vi.fn();
23+
render(
24+
<CountrySelector countryCode="US +1" setCountryCode={setCountryCode} />,
25+
);
26+
27+
const selectElement = screen.getByRole("combobox");
28+
fireEvent.change(selectElement, { target: { value: "CA +1" } });
29+
30+
expect(setCountryCode).toHaveBeenCalledWith("CA +1");
31+
});
32+
33+
it("displays all supported countries", () => {
34+
const setCountryCode = vi.fn();
35+
render(
36+
<CountrySelector countryCode="US +1" setCountryCode={setCountryCode} />,
37+
);
38+
39+
const options = screen.getAllByRole("option");
40+
expect(options.length).toBeGreaterThan(0);
41+
expect(
42+
options.some((option) => option.textContent?.includes("United States")),
43+
).toBe(true);
44+
});
45+
});

packages/thirdweb/src/react/web/wallets/in-app/CountrySelector.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
"use client";
2-
import { useQuery } from "@tanstack/react-query";
32
import { useRef } from "react";
43
import { useCustomTheme } from "../../../core/design-system/CustomThemeProvider.js";
54
import { radius, spacing } from "../../../core/design-system/index.js";
65
import { StyledOption, StyledSelect } from "../../ui/design-system/elements.js";
6+
import {
7+
type SupportedSmsCountry,
8+
supportedSmsCountries,
9+
} from "./supported-sms-countries.js";
10+
11+
export function getCountrySelector(countryIsoCode: SupportedSmsCountry) {
12+
const country = supportedSmsCountries.find(
13+
(country) => country.countryIsoCode === countryIsoCode,
14+
);
15+
if (!country) {
16+
return "US +1";
17+
}
18+
return `${country.countryIsoCode} +${country.phoneNumberCode}`;
19+
}
720

821
export function CountrySelector({
922
countryCode,
@@ -14,17 +27,7 @@ export function CountrySelector({
1427
}) {
1528
const selectRef = useRef<HTMLSelectElement>(null);
1629

17-
const { data: supportedCountries } = useQuery({
18-
queryKey: ["supported-sms-countries"],
19-
queryFn: async () => {
20-
const { supportedSmsCountries } = await import(
21-
"./supported-sms-countries.js"
22-
);
23-
return supportedSmsCountries;
24-
},
25-
});
26-
27-
const supportedCountriesForSms = supportedCountries ?? [
30+
const supportedCountriesForSms = supportedSmsCountries ?? [
2831
{
2932
countryIsoCode: "US",
3033
countryName: "United States",
@@ -58,7 +61,7 @@ export function CountrySelector({
5861
return (
5962
<Option
6063
key={country.countryIsoCode}
61-
value={`${country.countryIsoCode} +${country.phoneNumberCode}`}
64+
value={getCountrySelector(country.countryIsoCode)}
6265
>
6366
{country.countryName} +{country.phoneNumberCode}
6467
</Option>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { describe, expect, it, vi } from "vitest";
2+
import { render, screen } from "../../../../../test/src/react-render.js";
3+
import { getCountrySelector } from "./CountrySelector.js";
4+
import { InputSelectionUI } from "./InputSelectionUI.js";
5+
6+
vi.mock("./CountrySelector.js", async (importOriginal) => ({
7+
...(await importOriginal()),
8+
getCountrySelector: vi.fn(),
9+
}));
10+
11+
describe("InputSelectionUI", () => {
12+
it("should initialize countryCodeInfo with defaultSmsCountryCode", () => {
13+
const mockGetCountrySelector = vi.mocked(getCountrySelector);
14+
mockGetCountrySelector.mockReturnValue("CA +1");
15+
16+
render(
17+
<InputSelectionUI
18+
defaultSmsCountryCode="CA"
19+
onSelect={vi.fn()}
20+
placeholder=""
21+
name=""
22+
type=""
23+
submitButtonText=""
24+
format="phone"
25+
/>,
26+
);
27+
28+
expect(screen.getByRole("combobox")).toHaveValue("CA +1");
29+
});
30+
31+
it('should initialize countryCodeInfo with "US +1" if defaultSmsCountryCode is not provided', () => {
32+
render(
33+
<InputSelectionUI
34+
onSelect={vi.fn()}
35+
placeholder=""
36+
name=""
37+
type=""
38+
submitButtonText=""
39+
format="phone"
40+
/>,
41+
);
42+
43+
expect(screen.getByRole("combobox")).toHaveValue("US +1");
44+
});
45+
});

packages/thirdweb/src/react/web/wallets/in-app/InputSelectionUI.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import { Spacer } from "../../ui/components/Spacer.js";
1010
import { IconButton } from "../../ui/components/buttons.js";
1111
import { Input, InputContainer } from "../../ui/components/formElements.js";
1212
import { Text } from "../../ui/components/text.js";
13-
import { CountrySelector } from "./CountrySelector.js";
13+
import { CountrySelector, getCountrySelector } from "./CountrySelector.js";
14+
import type { SupportedSmsCountry } from "./supported-sms-countries.js";
1415

1516
export function InputSelectionUI(props: {
1617
onSelect: (data: string) => void;
@@ -22,8 +23,13 @@ export function InputSelectionUI(props: {
2223
submitButtonText: string;
2324
format?: "phone";
2425
disabled?: boolean;
26+
defaultSmsCountryCode?: SupportedSmsCountry;
2527
}) {
26-
const [countryCodeInfo, setCountryCodeInfo] = useState("US +1");
28+
const [countryCodeInfo, setCountryCodeInfo] = useState(
29+
props.defaultSmsCountryCode
30+
? getCountrySelector(props.defaultSmsCountryCode)
31+
: "US +1",
32+
);
2733
const [input, setInput] = useState("");
2834
const [error, setError] = useState<string | undefined>();
2935
const [showError, setShowError] = useState(false);

packages/thirdweb/src/react/web/wallets/in-app/supported-sms-countries.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
export type SupportedSmsCountry =
2+
(typeof supportedSmsCountries)[number]["countryIsoCode"];
13
export const supportedSmsCountries = [
24
{
35
countryIsoCode: "AD",
@@ -1183,4 +1185,4 @@ export const supportedSmsCountries = [
11831185
countryName: "Zimbabwe",
11841186
phoneNumberCode: "263",
11851187
},
1186-
];
1188+
] as const;

packages/thirdweb/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ export const ConnectWalletSocialOptions = (
448448
disabled={props.disabled}
449449
emptyErrorMessage={emptyErrorMessage}
450450
submitButtonText={locale.submitEmail}
451+
defaultSmsCountryCode={
452+
wallet.getConfig()?.auth?.defaultSmsCountryCode
453+
}
451454
/>
452455
) : (
453456
<WalletTypeRowButton

packages/thirdweb/src/wallets/ecosystem/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { SupportedSmsCountry } from "../../react/web/wallets/in-app/supported-sms-countries.js";
12
import type {
23
InAppWalletAutoConnectOptions,
34
InAppWalletConnectionOptions,
@@ -13,6 +14,10 @@ export type EcosystemWalletCreationOptions = {
1314
* Optional url to redirect to after authentication
1415
*/
1516
redirectUrl?: string;
17+
/**
18+
* The default country code to use for SMS authentication
19+
*/
20+
defaultSmsCountryCode?: SupportedSmsCountry;
1621
};
1722
/**
1823
* The partnerId of the ecosystem wallet to connect to

packages/thirdweb/src/wallets/in-app/core/wallet/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Chain } from "../../../../chains/types.js";
22
import type { ThirdwebClient } from "../../../../client/client.js";
3+
import type { SupportedSmsCountry } from "../../../../react/web/wallets/in-app/supported-sms-countries.js";
34
import type { SmartWalletOptions } from "../../../smart/types.js";
45
import type {
56
AuthOption,
@@ -59,6 +60,10 @@ export type InAppWalletCreationOptions =
5960
* The domain of the passkey to use for authentication
6061
*/
6162
passkeyDomain?: string;
63+
/**
64+
* The default country code to use for SMS authentication
65+
*/
66+
defaultSmsCountryCode?: SupportedSmsCountry;
6267
};
6368
/**
6469
* Metadata to display in the Connect Modal

0 commit comments

Comments
 (0)