diff --git a/web/app/(app)/(auth)/verify-email/page.tsx b/web/app/(app)/(auth)/verify-email/page.tsx index 841642e..813a7fe 100644 --- a/web/app/(app)/(auth)/verify-email/page.tsx +++ b/web/app/(app)/(auth)/verify-email/page.tsx @@ -1,7 +1,7 @@ 'use client' import { useState, useEffect } from 'react' -import { useSearchParams } from 'next/navigation' +import { useSearchParams, useRouter } from 'next/navigation' import Link from 'next/link' import { Button } from '@/components/ui/button' import { @@ -14,11 +14,12 @@ import { } from '@/components/ui/card' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Loader2, CheckCircle, XCircle, Mail, ArrowRight } from 'lucide-react' -import { useMutation } from '@tanstack/react-query' +import { useMutation, useQuery } from '@tanstack/react-query' import httpBrowserClient from '@/lib/httpBrowserClient' import { ApiEndpoints } from '@/config/api' import { Routes } from '@/config/routes' +// Reusable components const ErrorAlert = ({ message }: { message: string }) => ( ( ) -const SendVerificationButton = ({ - onClick, - isLoading, - hasVerificationCode, -}: { - onClick: () => void - isLoading: boolean - hasVerificationCode: boolean -}) => ( - +) + +const LoginButton = () => ( + ) -const SendVerificationEmail = () => { +export default function VerifyEmailPage() { + const router = useRouter() + const searchParams = useSearchParams() + const userId = searchParams.get('userId') + const verificationCode = searchParams.get('verificationCode') + const verificationEmailSent = searchParams.get('verificationEmailSent') + const [successMessage, setSuccessMessage] = useState('') - const [error, setError] = useState('') + const [errorMessage, setErrorMessage] = useState('') + + // Check user authentication and email verification status + const { + data: whoAmIData, + isPending: isCheckingAuth, + isError: isAuthError + } = useQuery({ + queryKey: ['whoAmI'], + queryFn: () => httpBrowserClient.get(ApiEndpoints.auth.whoAmI()), + retry: 1, + }) + + const user = whoAmIData?.data?.data + const isEmailVerified = !!user?.emailVerifiedAt + const isLoggedIn = !isAuthError && !!user - const { - mutate: sendVerificationEmailMutation, - isPending: isSendingVerificationEmail, + // Verify email mutation + const { + mutate: verifyEmail, + isPending: isVerifying } = useMutation({ - mutationFn: () => - httpBrowserClient.post( - ApiEndpoints.auth.sendEmailVerificationEmail(), - {} - ), + mutationFn: () => httpBrowserClient.post('/auth/verify-email', { + userId, + verificationCode, + }), onSuccess: () => { - setSuccessMessage('Verification email has been sent to your inbox') + setSuccessMessage('Your email has been successfully verified') + setErrorMessage('') }, onError: (error: any) => { - setError(error.message || 'Failed to send verification email') + setErrorMessage(error.message || 'Failed to verify email') }, }) - const renderContent = () => { - if (successMessage) - return ( - - - Email Sent - {successMessage} - - ) - if (error) return - return null - } - - return ( - - - Email Verification - - Send a verification email to verify your account - - - {renderContent()} - - sendVerificationEmailMutation()} - isLoading={isSendingVerificationEmail} - hasVerificationCode={false} - /> - - - ) -} - -const VerifyEmail = ({ - userId, - verificationCode, -}: { - userId: string - verificationCode: string -}) => { - const [successMessage, setSuccessMessage] = useState('') - const [error, setError] = useState('') - const [isVerified, setIsVerified] = useState(false) - - const { mutate: verifyEmailMutation, isPending: isVerifyingEmail } = - useMutation({ - mutationFn: () => - httpBrowserClient.post('/auth/verify-email', { - userId, - verificationCode, - }), - onSuccess: () => { - setIsVerified(true) - setSuccessMessage('Your email has been successfully verified') - }, - onError: (error: any) => { - setError(error.message || 'Failed to verify email') - }, - }) + // Send verification email mutation + const { + mutate: sendVerificationEmail, + isPending: isSending + } = useMutation({ + mutationFn: () => httpBrowserClient.post( + ApiEndpoints.auth.sendEmailVerificationEmail(), + {} + ), + onSuccess: () => { + if (!verificationEmailSent) { + router.push('/verify-email?verificationEmailSent=true') + } else { + setSuccessMessage('Verification email has been sent to your inbox') + setErrorMessage('') + } + }, + onError: (error: any) => { + setErrorMessage(error.message || 'Failed to send verification email') + }, + }) + // Handle verification when code is provided useEffect(() => { - verifyEmailMutation() - }, [verifyEmailMutation]) + if (userId && verificationCode && !isVerifying && !successMessage && !errorMessage) { + if (isEmailVerified) { + setSuccessMessage('Your email has already been verified') + } else if (!isCheckingAuth) { + verifyEmail() + } + } + }, [userId, verificationCode, isCheckingAuth, isEmailVerified, isVerifying, successMessage, errorMessage, verifyEmail]) + // Render content based on current state const renderContent = () => { - if (isVerifyingEmail) + // Show loading state + if (isCheckingAuth) { return ( -
- -
+ <> + + Email Verification + Checking verification status... + + + + + ) - if (isVerified) + } + + // Handle verification process + if (userId && verificationCode) { return ( - - - Success - -
-
{successMessage}
- - Go to Dashboard - -
-
-
+ <> + + Email Verification + + {isVerifying ? 'Verifying your email address...' : 'Email Verification Status'} + + + + {isVerifying ? ( + + ) : successMessage ? ( + + ) : errorMessage ? ( + + ) : null} + + + {successMessage && } + + ) - if (error) return - return null - } - - return ( - - - Email Verification - Verifying your email address... - - {renderContent()} - - {isVerified && ( - - )} - - - ) -} - -const CheckEmailPrompt = () => { - const { - mutate: sendVerificationEmailMutation, - isPending, - isError, - isSuccess, - } = useMutation({ - mutationFn: () => - httpBrowserClient.post( - ApiEndpoints.auth.sendEmailVerificationEmail(), - {} - ), - }) + } - return ( - - - Check your email - - We've sent you a verification email. Please check your inbox and click - the link to verify your account. - - - - {isSuccess && ( - - - - Email Sent - - - A new verification email has been sent to your inbox - - - )} - {isError && ( - - - Error - - Failed to resend verification email - - - )} - - -
- - Didn't receive the email? - - +
)} - - -
-
- ) -} + + + ) + } -export default function VerifyEmailPage() { - const searchParams = useSearchParams() - const userId = searchParams.get('userId') - const verificationCode = searchParams.get('verificationCode') - const verificationEmailSent = searchParams.get('verificationEmailSent') + // Handle "send verification email" state + return ( + <> + + Email Verification + + {isLoggedIn + ? isEmailVerified + ? 'Your email is already verified' + : 'Verify your email address to access all features' + : 'You need to be logged in to verify your email' + } + + + + {successMessage && ( + + )} + {errorMessage && ( + + )} + {isEmailVerified && ( + + )} + {!isLoggedIn && ( + + + Not Logged In + + You need to be logged in to verify your email + + + )} + + + {isLoggedIn ? ( + isEmailVerified ? ( + + ) : ( + + ) + ) : ( + + )} + + + ) + } return (
- {userId && verificationCode ? ( - - ) : verificationEmailSent ? ( - - ) : ( - - )} + + {renderContent()} +
) }