import { Card, useThemeColor } from "heroui-native"; import { useAuthActions } from "@convex-dev/auth/react"; import { useState } from "react"; import { ActivityIndicator, Alert, Pressable, Text, TextInput, View, } from "react-native"; export function SignIn() { const { signIn } = useAuthActions(); const [authMethod, setAuthMethod] = useState<"phone" | "email" | "password">("phone"); const [step, setStep] = useState<"signIn" | { phone: string } | { email: string }>("signIn"); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const mutedColor = useThemeColor("muted"); const accentColor = useThemeColor("accent"); const foregroundColor = useThemeColor("foreground"); const dangerColor = useThemeColor("danger"); const handleSendPhoneCode = async (phone: string) => { setIsLoading(true); setError(null); try { const formData = new FormData(); formData.append("phone", phone); await signIn("twilio", formData); setStep({ phone }); Alert.alert("Success", `Verification code sent to ${phone}`); } catch (err) { const errorMessage = "Failed to send verification code"; setError(errorMessage); Alert.alert("Error", errorMessage); } finally { setIsLoading(false); } }; const handleVerifyPhoneCode = async (code: string, phone: string) => { setIsLoading(true); setError(null); try { const formData = new FormData(); formData.append("code", code); formData.append("phone", phone); await signIn("twilio", formData); Alert.alert("Success", "Successfully signed in!"); } catch (err) { const errorMessage = "Invalid verification code"; setError(errorMessage); Alert.alert("Error", errorMessage); } finally { setIsLoading(false); } }; const handleSendCode = async (email: string) => { setIsLoading(true); setError(null); try { const formData = new FormData(); formData.append("email", email); await signIn("resend-otp", formData); setStep({ email }); Alert.alert("Success", `Verification code sent to ${email}`); } catch (err) { const errorMessage = "Failed to send verification code"; setError(errorMessage); Alert.alert("Error", errorMessage); } finally { setIsLoading(false); } }; const handleVerifyCode = async (code: string, email: string) => { setIsLoading(true); setError(null); try { const formData = new FormData(); formData.append("code", code); formData.append("email", email); await signIn("resend-otp", formData); Alert.alert("Success", "Successfully signed in!"); } catch (err) { const errorMessage = "Invalid verification code"; setError(errorMessage); Alert.alert("Error", errorMessage); } finally { setIsLoading(false); } }; const handlePasswordAuth = async (email: string, password: string, flow: "signIn" | "signUp") => { console.log("Password auth started:", { email, flow, passwordLength: password.length }); setIsLoading(true); setError(null); try { const formData = new FormData(); formData.append("email", email); formData.append("password", password); formData.append("flow", flow); console.log("FormData created, calling signIn..."); await signIn("password", formData); console.log("Sign in successful!"); Alert.alert("Success", `Successfully ${flow === "signIn" ? "signed in" : "signed up"}!`); } catch (err) { console.error("Password auth error:", err); let errorMessage: string; if (flow === "signIn") { errorMessage = "Could not sign in, did you mean to sign up?"; } else { errorMessage = "Could not sign up, did you mean to sign in?"; } setError(errorMessage); Alert.alert("Error", errorMessage); } finally { setIsLoading(false); } }; const getTitle = () => { if (step === "signIn") { return "Sign In or Create Account"; } if ('phone' in step) { return "Check Your Phone"; } return "Check Your Email"; }; return ( {getTitle()} {error && ( {error} )} {step === "signIn" ? ( <> setAuthMethod("phone")} className={`flex-1 p-3 rounded-l-lg ${ authMethod === "phone" ? "bg-accent" : "bg-surface" }`} > Phone setAuthMethod("email")} className={`flex-1 p-2 ${ authMethod === "email" ? "bg-accent" : "bg-surface" }`} > Email setAuthMethod("password")} className={`flex-1 p-3 rounded-r-lg ${ authMethod === "password" ? "bg-accent" : "bg-surface" }`} > Password {authMethod === "phone" ? ( ) : authMethod === "email" ? ( ) : ( )} ) : 'phone' in step ? ( setStep("signIn")} isLoading={isLoading} mutedColor={mutedColor} foregroundColor={foregroundColor} /> ) : ( setStep("signIn")} isLoading={isLoading} mutedColor={mutedColor} foregroundColor={foregroundColor} /> )} ); } function PhoneStep({ onSendCode, isLoading, mutedColor, foregroundColor }) { const [phone, setPhone] = useState(""); const handleSubmit = () => { if (phone.trim()) { onSendCode(phone); } }; return ( <> {isLoading ? ( ) : ( Send Code )} ); } function PhoneCodeStep({ phone, onVerifyCode, onCancel, isLoading, mutedColor, foregroundColor }) { const [code, setCode] = useState(""); const handleSubmit = () => { if (code.trim()) { onVerifyCode(code, phone); } }; return ( <> Enter the 6-digit code we sent to {phone} {isLoading ? ( ) : ( Continue )} Cancel ); } function EmailStep({ onSendCode, isLoading, mutedColor, foregroundColor }) { const [email, setEmail] = useState(""); const handleSubmit = () => { if (email.trim()) { onSendCode(email); } }; return ( <> {isLoading ? ( ) : ( Send Code )} ); } function CodeStep({ email, onVerifyCode, onCancel, isLoading, mutedColor, foregroundColor }) { const [code, setCode] = useState(""); const handleSubmit = () => { if (code.trim()) { onVerifyCode(code, email); } }; return ( <> Enter the verification code sent to {email} {isLoading ? ( ) : ( Continue )} Cancel ); } function PasswordStep({ onPasswordAuth, isLoading, mutedColor, foregroundColor }) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [flow, setFlow] = useState<"signIn" | "signUp">("signIn"); const handleSubmit = () => { console.log("Password submit clicked:", { email, passwordLength: password.length, flow }); if (!email.trim()) { Alert.alert("Error", "Please enter your email"); return; } if (!password.trim()) { Alert.alert("Error", "Please enter your password"); return; } if (password.length < 6) { Alert.alert("Error", "Password must be at least 6 characters"); return; } console.log("Validation passed, calling onPasswordAuth..."); onPasswordAuth(email, password, flow); }; return ( <> { console.log("Email changed:", text); setEmail(text); }} placeholderTextColor={mutedColor} keyboardType="email-address" autoCapitalize="none" autoComplete="email" /> { console.log("Password changed, length:", text.length); setPassword(text); }} placeholderTextColor={mutedColor} secureTextEntry autoComplete={flow === "signIn" ? "current-password" : "new-password"} /> { console.log("Submit button pressed"); handleSubmit(); }} disabled={isLoading} className={`mb-3 flex-row items-center justify-center rounded-lg p-4 ${ isLoading || !email.trim() || !password.trim() ? "bg-gray-400 opacity-50" : "bg-accent active:opacity-70" }`} > {isLoading ? ( ) : ( {flow === "signIn" ? "Sign In" : "Sign Up"} )} { console.log("Flow toggle clicked, current flow:", flow); setFlow(flow === "signIn" ? "signUp" : "signIn"); }} disabled={isLoading} className="flex-row items-center justify-center p-2" > {flow === "signIn" ? "Don't have an account? Sign up" : "Already have an account? Sign in" } ); }