email verfication after account creation, password component, added password special characters

This commit is contained in:
jackiettran
2025-10-10 14:36:09 -04:00
parent 513347e8b7
commit 0a9b875a9d
19 changed files with 1305 additions and 86 deletions

View File

@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { Link, useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import PasswordInput from '../components/PasswordInput';
const Login: React.FC = () => {
const [email, setEmail] = useState('');
@@ -54,19 +55,13 @@ const Login: React.FC = () => {
required
/>
</div>
<div className="mb-3">
<label htmlFor="password" className="form-label">
Password
</label>
<input
type="password"
className="form-control"
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
<PasswordInput
id="password"
label="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<button
type="submit"
className="btn btn-primary w-100"

View File

@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { Link, useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import PasswordInput from '../components/PasswordInput';
const Register: React.FC = () => {
const [formData, setFormData] = useState({
@@ -125,20 +126,14 @@ const Register: React.FC = () => {
onChange={handleChange}
/>
</div>
<div className="mb-3">
<label htmlFor="password" className="form-label">
Password
</label>
<input
type="password"
className="form-control"
id="password"
name="password"
value={formData.password}
onChange={handleChange}
required
/>
</div>
<PasswordInput
id="password"
name="password"
label="Password"
value={formData.password}
onChange={handleChange}
required
/>
<button
type="submit"
className="btn btn-primary w-100"

View File

@@ -0,0 +1,145 @@
import React, { useEffect, useState, useRef } from 'react';
import { useNavigate, useSearchParams, Link } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import { authAPI } from '../services/api';
const VerifyEmail: React.FC = () => {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const { checkAuth, user } = useAuth();
const [error, setError] = useState<string>('');
const [success, setSuccess] = useState(false);
const [processing, setProcessing] = useState(true);
const [resending, setResending] = useState(false);
const hasProcessed = useRef(false);
useEffect(() => {
const handleVerification = async () => {
// Prevent double execution in React StrictMode
if (hasProcessed.current) {
return;
}
hasProcessed.current = true;
try {
const token = searchParams.get('token');
if (!token) {
setError('No verification token provided.');
setProcessing(false);
return;
}
// Verify the email with the token
await authAPI.verifyEmail(token);
setSuccess(true);
setProcessing(false);
// Refresh user data to update isVerified status
await checkAuth();
// Redirect to home after 3 seconds
setTimeout(() => {
navigate('/', { replace: true });
}, 3000);
} catch (err: any) {
console.error('Email verification error:', err);
const errorData = err.response?.data;
if (errorData?.code === 'VERIFICATION_TOKEN_EXPIRED') {
setError('Your verification link has expired. Please request a new one.');
} else if (errorData?.code === 'VERIFICATION_TOKEN_INVALID') {
setError('Invalid verification link. The link may have already been used or is incorrect.');
} else if (errorData?.code === 'ALREADY_VERIFIED') {
setError('Your email is already verified.');
} else {
setError(errorData?.error || 'Failed to verify email. Please try again.');
}
setProcessing(false);
}
};
handleVerification();
}, [searchParams, navigate, checkAuth]);
const handleResendVerification = async () => {
setResending(true);
setError('');
try {
await authAPI.resendVerification();
setError('');
alert('Verification email sent! Please check your inbox.');
} catch (err: any) {
console.error('Resend verification error:', err);
const errorData = err.response?.data;
if (errorData?.code === 'ALREADY_VERIFIED') {
setError('Your email is already verified.');
} else if (errorData?.code === 'NO_TOKEN') {
setError('You must be logged in to resend the verification email.');
} else {
setError(errorData?.error || 'Failed to resend verification email. Please try again.');
}
} finally {
setResending(false);
}
};
return (
<div className="container">
<div className="row justify-content-center mt-5">
<div className="col-md-6">
<div className="card">
<div className="card-body text-center py-5">
{processing ? (
<>
<div className="spinner-border text-primary mb-3" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<h5>Verifying Your Email...</h5>
<p className="text-muted">Please wait while we verify your email address.</p>
</>
) : success ? (
<>
<i className="bi bi-check-circle text-success" style={{ fontSize: '3rem' }}></i>
<h5 className="mt-3">Email Verified Successfully!</h5>
<p className="text-muted">
Your email has been verified. You will be redirected to the home page shortly.
</p>
<Link to="/" className="btn btn-primary mt-3">
Go to Home
</Link>
</>
) : error ? (
<>
<i className="bi bi-exclamation-circle text-danger" style={{ fontSize: '3rem' }}></i>
<h5 className="mt-3">Verification Failed</h5>
<p className="text-danger">{error}</p>
<div className="mt-3">
{user && !error.includes('already verified') && (
<button
className="btn btn-primary me-2"
onClick={handleResendVerification}
disabled={resending}
>
{resending ? 'Sending...' : 'Resend Verification Email'}
</button>
)}
<Link to="/" className="btn btn-outline-secondary">
Return to Home
</Link>
</div>
</>
) : null}
</div>
</div>
</div>
</div>
</div>
);
};
export default VerifyEmail;