Compare commits
2 Commits
4f85243815
...
2e18137b5b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e18137b5b | ||
|
|
36cf5b65fa |
@@ -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,
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
38
frontend/src/pages/NotFound.tsx
Normal file
38
frontend/src/pages/NotFound.tsx
Normal 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;
|
||||||
@@ -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>
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user