diff --git a/.changeset/bumpy-ducks-travel.md b/.changeset/bumpy-ducks-travel.md new file mode 100644 index 00000000000..133979d00ee --- /dev/null +++ b/.changeset/bumpy-ducks-travel.md @@ -0,0 +1,5 @@ +--- +"@thirdweb-dev/service-utils": patch +--- + +expose project.services.iaw.smsEnabledCountryISOs from api response diff --git a/apps/dashboard/src/@/api/sms.ts b/apps/dashboard/src/@/api/sms.ts new file mode 100644 index 00000000000..af97360dbbd --- /dev/null +++ b/apps/dashboard/src/@/api/sms.ts @@ -0,0 +1,53 @@ +import { API_SERVER_URL, THIRDWEB_API_SECRET } from "../constants/env"; + +export type SMSCountryTiers = { + tier1: string[]; + tier2: string[]; + tier3: string[]; + tier4: string[]; + tier5: string[]; +}; + +export async function getSMSCountryTiers() { + if (!THIRDWEB_API_SECRET) { + throw new Error("API_SERVER_SECRET is not set"); + } + const res = await fetch(`${API_SERVER_URL}/v1/sms/list-country-tiers`, { + headers: { + "Content-Type": "application/json", + "x-service-api-key": THIRDWEB_API_SECRET, + }, + next: { + revalidate: 15 * 60, //15 minutes + }, + }); + + if (!res.ok) { + console.error( + "Failed to fetch sms country tiers", + res.status, + res.statusText, + ); + res.body?.cancel(); + return { + tier1: [], + tier2: [], + tier3: [], + tier4: [], + tier5: [], + }; + } + + try { + return (await res.json()).data as SMSCountryTiers; + } catch (e) { + console.error("Failed to parse sms country tiers", e); + return { + tier1: [], + tier2: [], + tier3: [], + tier4: [], + tier5: [], + }; + } +} diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/in-app-wallets/settings/page.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/in-app-wallets/settings/page.tsx index 11968dcc72e..3d75c14b4cd 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/in-app-wallets/settings/page.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/in-app-wallets/settings/page.tsx @@ -1,4 +1,5 @@ import { getProject } from "@/api/projects"; +import { getSMSCountryTiers } from "@/api/sms"; import { getTeamBySlug } from "@/api/team"; import { redirect } from "next/navigation"; import { InAppWalletSettingsPage } from "../../../../../../../components/embedded-wallets/Configure"; @@ -9,9 +10,10 @@ export default async function Page(props: { }) { const { team_slug, project_slug } = await props.params; - const [team, project] = await Promise.all([ + const [team, project, smsCountryTiers] = await Promise.all([ getTeamBySlug(team_slug), getProject(team_slug, project_slug), + getSMSCountryTiers(), ]); if (!team) { @@ -29,6 +31,7 @@ export default async function Page(props: { trackingCategory="in-app-wallet-project-settings" teamSlug={team_slug} validTeamPlan={getValidTeamPlan(team)} + smsCountryTiers={smsCountryTiers} /> ); } diff --git a/apps/dashboard/src/components/embedded-wallets/Configure/InAppWalletSettingsUI.stories.tsx b/apps/dashboard/src/components/embedded-wallets/Configure/InAppWalletSettingsUI.stories.tsx index a09a1842846..f8f2c934f38 100644 --- a/apps/dashboard/src/components/embedded-wallets/Configure/InAppWalletSettingsUI.stories.tsx +++ b/apps/dashboard/src/components/embedded-wallets/Configure/InAppWalletSettingsUI.stories.tsx @@ -64,6 +64,14 @@ function Variants(props: { isUpdating={false} trackingCategory="foo" updateApiKey={() => {}} + smsCountryTiers={{ + // scaffold some countries to play around with the UI + tier1: ["US", "CA"], + tier2: ["GB", "AU", "NZ"], + tier3: ["FR", "DE", "ES", "IT"], + tier4: ["JP", "KR", "MX", "RU"], + tier5: ["BR", "AR", "CO", "CL", "PE", "VE", "SA"], + }} /> diff --git a/apps/dashboard/src/components/embedded-wallets/Configure/index.tsx b/apps/dashboard/src/components/embedded-wallets/Configure/index.tsx index aa2ca66a4d2..cd35d7f432f 100644 --- a/apps/dashboard/src/components/embedded-wallets/Configure/index.tsx +++ b/apps/dashboard/src/components/embedded-wallets/Configure/index.tsx @@ -1,6 +1,7 @@ "use client"; import type { Project } from "@/api/projects"; +import type { SMSCountryTiers } from "@/api/sms"; import { DynamicHeight } from "@/components/ui/DynamicHeight"; import { Spinner } from "@/components/ui/Spinner/Spinner"; import { UnderlineLink } from "@/components/ui/UnderlineLink"; @@ -36,6 +37,7 @@ import { type UseFormReturn, useFieldArray, useForm } from "react-hook-form"; import { toast } from "sonner"; import { toArrFromList } from "utils/string"; import type { Team } from "../../../@/api/team"; +import CountrySelector from "./sms-country-select/country-selector"; type InAppWalletSettingsPageProps = { trackingCategory: string; @@ -43,6 +45,7 @@ type InAppWalletSettingsPageProps = { teamId: string; teamSlug: string; validTeamPlan: Team["billingPlan"]; + smsCountryTiers: SMSCountryTiers; }; const TRACKING_CATEGORY = "embedded-wallet"; @@ -108,6 +111,7 @@ export function InAppWalletSettingsPage(props: InAppWalletSettingsPageProps) { canEditAdvancedFeatures={props.validTeamPlan !== "free"} updateApiKey={handleUpdateProject} isUpdating={updateProject.isPending} + smsCountryTiers={props.smsCountryTiers} /> ); } @@ -120,6 +124,7 @@ const InAppWalletSettingsPageUI: React.FC< trackingData: UpdateAPIKeyTrackingData, ) => void; isUpdating: boolean; + smsCountryTiers: SMSCountryTiers; } > = (props) => { const embeddedWalletService = props.project.services.find( @@ -185,6 +190,11 @@ export const InAppWalletSettingsUI: React.FC< } : undefined), redirectUrls: (config.redirectUrls || []).join("\n"), + smsEnabledCountryISOs: config.smsEnabledCountryISOs + ? config.smsEnabledCountryISOs + : canEditAdvancedFeatures + ? ["US", "CA"] + : [], }, }); @@ -228,6 +238,7 @@ export const InAppWalletSettingsUI: React.FC< applicationImageUrl: branding?.applicationImageUrl, applicationName: branding?.applicationName || props.project.name, redirectUrls: toArrFromList(redirectUrls || "", true), + smsEnabledCountryISOs: values.smsEnabledCountryISOs, }; }); @@ -256,6 +267,8 @@ export const InAppWalletSettingsUI: React.FC< canEditAdvancedFeatures={canEditAdvancedFeatures} /> + + {/* Authentication */}
-
- +
+ + +