From 116975286f13d315b008f1f79f077ed04c2088a5 Mon Sep 17 00:00:00 2001 From: MananTank Date: Fri, 12 Dec 2025 17:08:22 +0000 Subject: [PATCH] [MNY-327] SDK: Display error returned from API in login with phone number UI (#8548) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR focuses on improving error handling and state management in the OTP authentication process. It enhances the way error messages are displayed and modifies the structure of `AccountStatus` to accommodate additional information. ### Detailed summary - In `otp.ts`, enhanced error handling by parsing the response for a detailed message. - Updated `AccountStatus` type in `OTPLoginUI.tsx` to an object structure, allowing for an error message. - Modified state management for `accountStatus` to use the new object structure. - Adjusted UI rendering logic to handle the new `AccountStatus` format. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` ## Summary by CodeRabbit * **Bug Fixes** * Enhanced error message handling in OTP verification to display detailed server error messages to users instead of generic messages. * Improved error status display in OTP login interface. * **Style** * Updated OTP login UI layout and spacing for better status presentation. ✏️ Tip: You can customize this high-level summary in your review settings. --- .../react/web/wallets/shared/OTPLoginUI.tsx | 35 +++++++++++++------ .../src/wallets/in-app/web/lib/auth/otp.ts | 12 ++++++- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/thirdweb/src/react/web/wallets/shared/OTPLoginUI.tsx b/packages/thirdweb/src/react/web/wallets/shared/OTPLoginUI.tsx index 7aeffc41bb8..46bb91ff7fa 100644 --- a/packages/thirdweb/src/react/web/wallets/shared/OTPLoginUI.tsx +++ b/packages/thirdweb/src/react/web/wallets/shared/OTPLoginUI.tsx @@ -29,7 +29,10 @@ type VerificationStatus = | "valid" | "idle" | "payment_required"; -type AccountStatus = "sending" | "sent" | "error"; +type AccountStatus = + | { type: "sending" } + | { type: "sent" } + | { type: "error"; message: string | undefined }; type ScreenToShow = "base" | "enter-password-or-recovery-code"; /** @@ -52,7 +55,9 @@ export function OTPLoginUI(props: { const [otpInput, setOtpInput] = useState(""); const [verifyStatus, setVerifyStatus] = useState("idle"); const [error, setError] = useState(); - const [accountStatus, setAccountStatus] = useState("sending"); + const [accountStatus, setAccountStatus] = useState({ + type: "sending", + }); const [countdown, setCountdown] = useState(0); const ecosystem = isEcosystemWallet(wallet) ? { @@ -66,7 +71,7 @@ export function OTPLoginUI(props: { const sendEmailOrSms = useCallback(async () => { setOtpInput(""); setVerifyStatus("idle"); - setAccountStatus("sending"); + setAccountStatus({ type: "sending" }); try { if ("email" in userInfo) { @@ -76,7 +81,7 @@ export function OTPLoginUI(props: { email: userInfo.email, strategy: "email", }); - setAccountStatus("sent"); + setAccountStatus({ type: "sent" }); setCountdown(60); // Start 60-second countdown } else if ("phone" in userInfo) { await preAuthenticate({ @@ -85,7 +90,7 @@ export function OTPLoginUI(props: { phoneNumber: userInfo.phone, strategy: "phone", }); - setAccountStatus("sent"); + setAccountStatus({ type: "sent" }); setCountdown(60); // Start 60-second countdown } else { throw new Error("Invalid userInfo"); @@ -93,7 +98,10 @@ export function OTPLoginUI(props: { } catch (e) { console.error(e); setVerifyStatus("idle"); - setAccountStatus("error"); + setAccountStatus({ + type: "error", + message: e instanceof Error ? e.message : undefined, + }); } }, [props.client, userInfo, ecosystem]); @@ -317,19 +325,24 @@ export function OTPLoginUI(props: { {!isWideModal && } - - {accountStatus === "error" && ( + + {accountStatus.type === "error" && ( - {locale.emailLoginScreen.failedToSendCode} + {accountStatus.message || + locale.emailLoginScreen.failedToSendCode} )} - {accountStatus === "sending" && ( + {accountStatus.type === "sending" && ( )} - {accountStatus !== "sending" && ( + {accountStatus.type !== "sending" && ( => { }); if (!response.ok) { - throw new Error("Failed to send verification code"); + const raw = await response.text(); + let message: string | undefined; + try { + const parsed = JSON.parse(raw); + if (parsed && typeof parsed.message === "string") { + message = parsed.message; + } + } catch { + // ignore parse errors + } + throw new Error(message || "Failed to send verification code"); } return await response.json();