Files
membership-fe/src/pages/VerifyEmail.js
2025-12-13 00:58:39 +07:00

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;