diff --git a/src/App.tsx b/src/App.tsx
index ee4c2dc..953553a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -15,6 +15,7 @@ import { AccountLinking } from './pages/AccountLinking.tsx'
import { Login } from './pages/Login.tsx'
import { Register } from './pages/Register.tsx'
import { ForgotPassword } from './pages/ForgotPassword.tsx'
+import { VerifyEmail } from './pages/VerifyEmail.tsx'
const queryClient = new QueryClient({
defaultOptions: {
@@ -47,6 +48,7 @@ export default function App() {
} />
} />
} />
+ } />
diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx
index 960aa0a..ba039ba 100644
--- a/src/pages/Register.tsx
+++ b/src/pages/Register.tsx
@@ -8,6 +8,9 @@ export function Register() {
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
+ const [registrationComplete, setRegistrationComplete] = useState(false)
+ const [resendLoading, setResendLoading] = useState(false)
+ const [resendMessage, setResendMessage] = useState('')
const navigate = useNavigate()
async function handleSubmit(e: React.FormEvent) {
@@ -36,15 +39,7 @@ export function Register() {
throw new Error(authError.message ?? 'Registration failed')
}
- // After successful signUp, force a session fetch to confirm the cookie is set
- // before navigating to the protected route
- const sessionResult = await authClient.getSession()
- if (sessionResult.data) {
- navigate('/')
- } else {
- // Session not established — show success message and link to login
- setError('Account created! Please sign in.')
- }
+ setRegistrationComplete(true)
} catch {
setError('Registration failed. Please try again.')
} finally {
@@ -52,6 +47,49 @@ export function Register() {
}
}
+ async function handleResendVerification() {
+ setResendLoading(true)
+ setResendMessage('')
+ try {
+ const { error } = await authClient.sendVerificationEmail({ email })
+ if (error) {
+ setResendMessage('Failed to resend. Please try again.')
+ } else {
+ setResendMessage('Verification email sent!')
+ }
+ } finally {
+ setResendLoading(false)
+ }
+ }
+
+ if (registrationComplete) {
+ return (
+
+
Check your email
+
+ We sent a verification link to {email}. Click it to activate your account.
+
+
+ {resendMessage && (
+
{resendMessage}
+ )}
+
+ Already have an account?{' '}
+
+ Sign in
+
+
+
+ )
+ }
+
return (
Create Account
diff --git a/src/pages/VerifyEmail.tsx b/src/pages/VerifyEmail.tsx
new file mode 100644
index 0000000..d1c5fb3
--- /dev/null
+++ b/src/pages/VerifyEmail.tsx
@@ -0,0 +1,113 @@
+import { useEffect, useState } from "react";
+import { useNavigate, useSearchParams } from "react-router-dom";
+import { authClient } from "../lib/auth-client.ts";
+
+export function VerifyEmail() {
+ const [searchParams] = useSearchParams();
+ const navigate = useNavigate();
+ const [status, setStatus] = useState<"verifying" | "success" | "error">("verifying");
+ const [resendEmail, setResendEmail] = useState("");
+ const [showResend, setShowResend] = useState(false);
+ const [resending, setResending] = useState(false);
+ const [resendMessage, setResendMessage] = useState("");
+
+ useEffect(() => {
+ const token = searchParams.get("token");
+ const callbackURL = searchParams.get("callbackURL") || "/";
+
+ if (!token) {
+ setStatus("error");
+ return;
+ }
+
+ authClient.verifyEmail({ query: { token } })
+ .then(() => {
+ setStatus("success");
+ setTimeout(() => {
+ navigate(callbackURL);
+ }, 2000);
+ })
+ .catch(() => {
+ setStatus("error");
+ });
+ }, [searchParams, navigate]);
+
+ async function handleResend() {
+ if (!resendEmail) {
+ setResendMessage("Please enter your email address.");
+ return;
+ }
+
+ setResending(true);
+ setResendMessage("");
+
+ try {
+ const { error } = await authClient.sendVerificationEmail({ email: resendEmail });
+ if (error) {
+ setResendMessage("Failed to resend. Please try again.");
+ } else {
+ setResendMessage("Verification email sent!");
+ setShowResend(false);
+ }
+ } finally {
+ setResending(false);
+ }
+ }
+
+ return (
+
+ {status === "verifying" && (
+ <>
+
+
Verifying your email...
+
Please wait while we verify your email address.
+ >
+ )}
+
+ {status === "success" && (
+ <>
+
Email verified!
+
Redirecting you shortly...
+ >
+ )}
+
+ {status === "error" && (
+ <>
+
Verification failed
+
The verification link may have expired or is invalid.
+
+ {!showResend ? (
+
+ ) : (
+
+
setResendEmail(e.target.value)}
+ className="min-h-12 w-full rounded-xl border border-gray-200 px-4 text-base focus:border-brand-blue focus:outline-none focus:ring-1 focus:ring-brand-blue"
+ />
+
+ {resendMessage && (
+
{resendMessage}
+ )}
+
+ )}
+ >
+ )}
+
+ );
+}