Compare commits

...

2 Commits

Author SHA1 Message Date
jackiettran
2e18137b5b 404 page 2025-12-25 23:32:55 -05:00
jackiettran
36cf5b65fa improved email verification experience wording 2025-12-25 23:09:10 -05:00
5 changed files with 72 additions and 27 deletions

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Verify Your Email - Village Share</title> <title>Verify Your Email</title>
<style> <style>
/* Reset styles */ /* Reset styles */
body, body,

View File

@@ -27,6 +27,7 @@ import CreateForumPost from './pages/CreateForumPost';
import MyPosts from './pages/MyPosts'; import MyPosts from './pages/MyPosts';
import EarningsDashboard from './pages/EarningsDashboard'; import EarningsDashboard from './pages/EarningsDashboard';
import FAQ from './pages/FAQ'; import FAQ from './pages/FAQ';
import NotFound from './pages/NotFound';
import PrivateRoute from './components/PrivateRoute'; import PrivateRoute from './components/PrivateRoute';
import axios from 'axios'; import axios from 'axios';
import './App.css'; import './App.css';
@@ -184,6 +185,7 @@ const AppContent: React.FC = () => {
} }
/> />
<Route path="/faq" element={<FAQ />} /> <Route path="/faq" element={<FAQ />} />
<Route path="*" element={<NotFound />} />
</Routes> </Routes>
</main> </main>
<Footer /> <Footer />

View File

@@ -42,14 +42,6 @@ const VerificationCodeModal: React.FC<VerificationCodeModalProps> = ({
} }
}, [show]); }, [show]);
// Clear resend success message after 3 seconds
useEffect(() => {
if (resendSuccess) {
const timer = setTimeout(() => setResendSuccess(false), 3000);
return () => clearTimeout(timer);
}
}, [resendSuccess]);
const handleInputChange = (index: number, value: string) => { const handleInputChange = (index: number, value: string) => {
// Only allow digits // Only allow digits
if (value && !/^\d$/.test(value)) return; if (value && !/^\d$/.test(value)) return;
@@ -58,6 +50,7 @@ const VerificationCodeModal: React.FC<VerificationCodeModalProps> = ({
newCode[index] = value; newCode[index] = value;
setCode(newCode); setCode(newCode);
setError(""); setError("");
setResendSuccess(false);
// Auto-advance to next input // Auto-advance to next input
if (value && index < 5) { if (value && index < 5) {
@@ -92,6 +85,7 @@ const VerificationCodeModal: React.FC<VerificationCodeModalProps> = ({
const handleVerify = async (verificationCode: string) => { const handleVerify = async (verificationCode: string) => {
setLoading(true); setLoading(true);
setError(""); setError("");
setResendSuccess(false);
try { try {
await authAPI.verifyEmail(verificationCode); await authAPI.verifyEmail(verificationCode);
@@ -101,11 +95,13 @@ const VerificationCodeModal: React.FC<VerificationCodeModalProps> = ({
} catch (err: any) { } catch (err: any) {
const errorData = err.response?.data; const errorData = err.response?.data;
if (errorData?.code === "TOO_MANY_ATTEMPTS") { if (errorData?.code === "TOO_MANY_ATTEMPTS") {
setError("Too many attempts. Please request a new code."); setError("Too many attempts. Please request a new code below.");
} else if (errorData?.code === "VERIFICATION_EXPIRED") { } else if (errorData?.code === "VERIFICATION_EXPIRED") {
setError("Code expired. Please request a new one."); setError("Code expired. Please request a new code below.");
} else if (errorData?.code === "VERIFICATION_INVALID") { } else if (errorData?.code === "VERIFICATION_INVALID") {
setError("Invalid code. Please check and try again."); setError(
"That code didn't match. Please try again or request a new code below."
);
} else { } else {
setError(errorData?.error || "Verification failed. Please try again."); setError(errorData?.error || "Verification failed. Please try again.");
} }
@@ -187,7 +183,9 @@ const VerificationCodeModal: React.FC<VerificationCodeModalProps> = ({
{code.map((digit, index) => ( {code.map((digit, index) => (
<input <input
key={index} key={index}
ref={(el) => { inputRefs.current[index] = el; }} ref={(el) => {
inputRefs.current[index] = el;
}}
type="text" type="text"
inputMode="numeric" inputMode="numeric"
maxLength={1} maxLength={1}
@@ -229,10 +227,10 @@ const VerificationCodeModal: React.FC<VerificationCodeModalProps> = ({
disabled={resending || resendCooldown > 0} disabled={resending || resendCooldown > 0}
> >
{resendCooldown > 0 {resendCooldown > 0
? `Resend in ${resendCooldown}s` ? `Send in ${resendCooldown}s`
: resending : resending
? "Sending..." ? "Sending..."
: "Resend Code"} : "Send Code"}
</button> </button>
</div> </div>

View File

@@ -0,0 +1,38 @@
import React from "react";
import { Link } from "react-router-dom";
const NotFound: React.FC = () => {
return (
<div className="container mt-5 mb-5">
<div className="row justify-content-center">
<div className="col-md-8 col-lg-6 text-center">
<h3 className="text-muted mb-5">
We can't find the page you're looking for!
</h3>
<div className="d-flex flex-column gap-3">
<Link to="/" className="btn btn-primary btn-lg">
Go to Home Page
</Link>
<p className="text-muted mb-0">or go to one of these</p>
<div className="d-flex flex-wrap justify-content-center gap-2">
<Link to="/items" className="btn btn-outline-secondary">
Browse Items
</Link>
<Link to="/forum" className="btn btn-outline-secondary">
Community Forum
</Link>
<Link to="/faq" className="btn btn-outline-secondary">
FAQ
</Link>
</div>
</div>
</div>
</div>
</div>
);
};
export default NotFound;

View File

@@ -100,26 +100,34 @@ const VerifyEmail: React.FC = () => {
switch (code) { switch (code) {
case "VERIFICATION_EXPIRED": case "VERIFICATION_EXPIRED":
setError("Your verification code has expired. Please request a new one."); setError(
"Your verification code has expired. Please request a new code below."
);
setShowManualEntry(true); setShowManualEntry(true);
break; break;
case "VERIFICATION_INVALID": case "VERIFICATION_INVALID":
setError("Invalid verification code. Please check and try again."); setError(
"That code didn't match. Please try again or request a new code below."
);
setShowManualEntry(true); setShowManualEntry(true);
break; break;
case "TOO_MANY_ATTEMPTS": case "TOO_MANY_ATTEMPTS":
setError("Too many attempts. Please request a new code."); setError("Too many attempts. Please request a new code below.");
setShowManualEntry(true); setShowManualEntry(true);
break; break;
case "ALREADY_VERIFIED": case "ALREADY_VERIFIED":
setError("Your email is already verified."); setError("Your email is already verified.");
break; break;
case "NO_CODE": case "NO_CODE":
setError("No verification code found. Please request a new one."); setError(
"No verification code found. Please request a new code below."
);
setShowManualEntry(true); setShowManualEntry(true);
break; break;
default: default:
setError(errorData?.error || "Failed to verify email. Please try again."); setError(
errorData?.error || "Failed to verify email. Please try again."
);
setShowManualEntry(true); setShowManualEntry(true);
} }
}; };
@@ -260,7 +268,7 @@ const VerifyEmail: React.FC = () => {
shortly. shortly.
</p> </p>
<Link to="/" className="btn btn-success mt-3"> <Link to="/" className="btn btn-success mt-3">
Go to Home Go to Home Page
</Link> </Link>
</> </>
) : showManualEntry ? ( ) : showManualEntry ? (
@@ -294,7 +302,9 @@ const VerifyEmail: React.FC = () => {
{code.map((digit, index) => ( {code.map((digit, index) => (
<input <input
key={index} key={index}
ref={(el) => { inputRefs.current[index] = el; }} ref={(el) => {
inputRefs.current[index] = el;
}}
type="text" type="text"
inputMode="numeric" inputMode="numeric"
maxLength={1} maxLength={1}
@@ -343,7 +353,7 @@ const VerifyEmail: React.FC = () => {
? `Resend in ${resendCooldown}s` ? `Resend in ${resendCooldown}s`
: resending : resending
? "Sending..." ? "Sending..."
: "Resend Code"} : "Send Code"}
</button> </button>
</div> </div>
@@ -351,10 +361,7 @@ const VerifyEmail: React.FC = () => {
Check your spam folder if you don't see the email. Check your spam folder if you don't see the email.
</p> </p>
<Link <Link to="/" className="btn btn-outline-secondary mt-3">
to="/"
className="btn btn-outline-secondary mt-3"
>
Return to Home Return to Home
</Link> </Link>
</> </>