116 lines
4.2 KiB
JavaScript
116 lines
4.2 KiB
JavaScript
import React, { useEffect, useState, useRef } from 'react';
|
|
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
|
|
import axios from 'axios';
|
|
import { Button } from '../components/ui/button';
|
|
import { Card } from '../components/ui/card';
|
|
import { CheckCircle, XCircle, Loader2 } from 'lucide-react';
|
|
import PublicNavbar from '../components/PublicNavbar';
|
|
import PublicFooter from '../components/PublicFooter';
|
|
|
|
const API_URL = process.env.REACT_APP_BACKEND_URL;
|
|
|
|
const VerifyEmail = () => {
|
|
const navigate = useNavigate();
|
|
const [searchParams] = useSearchParams();
|
|
const [status, setStatus] = useState('loading');
|
|
const [message, setMessage] = useState('');
|
|
const token = searchParams.get('token');
|
|
const hasVerified = useRef(false);
|
|
|
|
useEffect(() => {
|
|
const verifyEmail = async () => {
|
|
// Prevent double execution in React StrictMode
|
|
if (hasVerified.current) {
|
|
return;
|
|
}
|
|
hasVerified.current = true;
|
|
|
|
if (!token) {
|
|
setStatus('error');
|
|
setMessage('Invalid verification link.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/auth/verify-email?token=${token}`);
|
|
setStatus('success');
|
|
setMessage(response.data.message);
|
|
} catch (error) {
|
|
setStatus('error');
|
|
setMessage(error.response?.data?.detail || 'Verification failed. Please try again.');
|
|
}
|
|
};
|
|
|
|
verifyEmail();
|
|
}, [token]);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white">
|
|
<PublicNavbar />
|
|
|
|
<div className="max-w-2xl mx-auto px-6 py-20">
|
|
<Card className="p-6 sm:p-8 md:p-12 bg-white rounded-2xl border border-[#ddd8eb] shadow-lg text-center">
|
|
{status === 'loading' && (
|
|
<>
|
|
<Loader2 className="h-20 w-20 text-[#664fa3] mx-auto mb-6 animate-spin" />
|
|
<h1 className="text-3xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
|
Verifying Your Email...
|
|
</h1>
|
|
<p className="text-lg text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Please wait while we verify your email address.
|
|
</p>
|
|
</>
|
|
)}
|
|
|
|
{status === 'success' && (
|
|
<>
|
|
<CheckCircle className="h-20 w-20 text-[#81B29A] mx-auto mb-6" />
|
|
<h1 className="text-3xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
|
Email Verified Successfully!
|
|
</h1>
|
|
<p className="text-lg text-[#664fa3] mb-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
{message}
|
|
</p>
|
|
<p className="text-base text-[#664fa3] mb-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
Next steps: Attend an event and meet a board member within 90 days. Once you've attended an event, our admin team will review your application.
|
|
</p>
|
|
<Link to="/login">
|
|
<Button
|
|
className="bg-[#DDD8EB] text-[#422268] hover:bg-white rounded-full px-12 py-6 text-lg font-medium shadow-lg"
|
|
data-testid="login-redirect-button"
|
|
>
|
|
Go to Login
|
|
</Button>
|
|
</Link>
|
|
</>
|
|
)}
|
|
|
|
{status === 'error' && (
|
|
<>
|
|
<XCircle className="h-20 w-20 text-red-500 mx-auto mb-6" />
|
|
<h1 className="text-3xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
|
|
Verification Failed
|
|
</h1>
|
|
<p className="text-lg text-[#664fa3] mb-8" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
|
|
{message}
|
|
</p>
|
|
<Link to="/">
|
|
<Button
|
|
className="bg-[#DDD8EB] text-[#422268] hover:bg-white rounded-full px-12 py-6 text-lg font-medium shadow-lg"
|
|
data-testid="home-redirect-button"
|
|
>
|
|
Go to Home
|
|
</Button>
|
|
</Link>
|
|
</>
|
|
)}
|
|
</Card>
|
|
</div>
|
|
|
|
<PublicFooter />
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default VerifyEmail;
|