feat(otp): mock phone OTP fallback while Twilio SMS is down

The Twilio sender isn't delivering, so gate the Verify step behind
NEXT_PUBLIC_MOCK_OTP (default true): 'Send code' skips Supabase/Twilio and a
fixed demo code (123456) verifies, with clear demo-mode copy. The real
addPhone/verifyPhone path is untouched — flip the flag to "false" to restore
live SMS verification.
This commit is contained in:
tanweer919
2026-07-13 13:59:04 +05:30
parent da7f7a7891
commit 27a5aa939e
+14 -2
View File
@@ -19,6 +19,12 @@ type Addr = { line1?: string; line2?: string; city?: string; state?: string; pos
const STEPS = ["Account", "Verify", "Address"];
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// Demo fallback for phone OTP while the Twilio sender is down. When on, the Verify
// step skips Supabase/Twilio and accepts a fixed code. Flip NEXT_PUBLIC_MOCK_OTP to
// "false" (or remove it) to restore real SMS verification — no other change needed.
const MOCK_OTP = process.env.NEXT_PUBLIC_MOCK_OTP === "true";
const DEMO_OTP = "123456";
export function RegisterFlow({ mode = "register" }: { mode?: "register" | "onboard" }) {
// "onboard" = an already-authenticated OAuth (Google) user completing their CRM
// profile: email is skipped (Google-verified), the auth account already exists so
@@ -390,6 +396,7 @@ function PhoneVerify({ cc, country, initialPhone, verified, onVerified }: {
if (value.replace(/\D/g, "").length !== country.digits) { setState("invalid_mobile"); return; }
setState("sending");
setOtpError("");
if (MOCK_OTP) { setState("sent"); return; } // demo: skip Twilio entirely
try {
await addPhone(e164); // Supabase → Twilio sends the SMS OTP
setState("sent");
@@ -400,6 +407,11 @@ function PhoneVerify({ cc, country, initialPhone, verified, onVerified }: {
async function submit(code: string) {
setOtpError("");
if (MOCK_OTP) {
if (code === DEMO_OTP) onVerified();
else setOtpError(`Demo mode — enter ${DEMO_OTP} to verify.`);
return;
}
try {
await verifyPhone(e164, code); // confirm the OTP (phone_change)
onVerified();
@@ -436,13 +448,13 @@ function PhoneVerify({ cc, country, initialPhone, verified, onVerified }: {
</div>
<div className="row between" style={{ marginTop: 12 }}>
<span className="faint" style={{ fontSize: 12 }}>Standard SMS rates may apply.</span>
<span className="faint" style={{ fontSize: 12 }}>{MOCK_OTP ? "Demo verification (no SMS sent)." : "Standard SMS rates may apply."}</span>
<button className="btn btn-sm" style={{ width: "auto" }} disabled={state === "sending" || state === "sent"} onClick={send}>
{state === "sending" ? "Sending…" : state === "sent" ? "Sent" : "Send code"}
</button>
</div>
{state === "sent" && <p className="faint" style={{ fontSize: 12, marginTop: 10 }}>Code sent to {cc} {value} by SMS.</p>}
{state === "sent" && <p className="faint" style={{ fontSize: 12, marginTop: 10 }}>{MOCK_OTP ? `Demo mode — enter ${DEMO_OTP} to verify (SMS temporarily disabled).` : `Code sent to ${cc} ${value} by SMS.`}</p>}
{state === "invalid_mobile" && <div style={{ marginTop: 10 }}><FlashNote tone="error">Enter a valid {country.digits}-digit mobile number.</FlashNote></div>}
{state === "send_error" && <div style={{ marginTop: 10 }}><FlashNote tone="error">Couldn&apos;t send the code. Check the number and try again.</FlashNote></div>}