Spaces:
Sleeping
Sleeping
Anish-530 commited on
Commit ·
1ce65dd
1
Parent(s): c041d0d
Graceful error message while logging in or registering through our system.
Browse files- frontend/app/login/page.tsx +51 -10
frontend/app/login/page.tsx
CHANGED
|
@@ -12,6 +12,7 @@ export default function LoginPage() {
|
|
| 12 |
const [username, setUsername] = useState("");
|
| 13 |
const [password, setPassword] = useState("");
|
| 14 |
const [verificationCode, setVerificationCode] = useState("");
|
|
|
|
| 15 |
const [error, setError] = useState("");
|
| 16 |
const [successMessage, setSuccessMessage] = useState("");
|
| 17 |
const [loading, setLoading] = useState(false);
|
|
@@ -67,6 +68,40 @@ export default function LoginPage() {
|
|
| 67 |
|
| 68 |
// Global Cursor is managed by components/shared/CustomCursor.tsx
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
const handleSubmit = async (e: React.FormEvent) => {
|
| 71 |
e.preventDefault();
|
| 72 |
setError("");
|
|
@@ -109,6 +144,9 @@ export default function LoginPage() {
|
|
| 109 |
setError(detail[0]?.msg || "Validation error. Please check your inputs.");
|
| 110 |
} else if (typeof detail === 'string') {
|
| 111 |
setError(detail);
|
|
|
|
|
|
|
|
|
|
| 112 |
} else {
|
| 113 |
setError("Server returned an unexpected error. Please try again.");
|
| 114 |
}
|
|
@@ -178,16 +216,19 @@ export default function LoginPage() {
|
|
| 178 |
|
| 179 |
<form onSubmit={handleSubmit} className="space-y-4">
|
| 180 |
{mode === 'verify' ? (
|
| 181 |
-
<div className="
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
|
|
|
|
|
|
|
|
|
| 191 |
</div>
|
| 192 |
) : (
|
| 193 |
<>
|
|
|
|
| 12 |
const [username, setUsername] = useState("");
|
| 13 |
const [password, setPassword] = useState("");
|
| 14 |
const [verificationCode, setVerificationCode] = useState("");
|
| 15 |
+
const [otp, setOtp] = useState(['', '', '', '', '', '']);
|
| 16 |
const [error, setError] = useState("");
|
| 17 |
const [successMessage, setSuccessMessage] = useState("");
|
| 18 |
const [loading, setLoading] = useState(false);
|
|
|
|
| 68 |
|
| 69 |
// Global Cursor is managed by components/shared/CustomCursor.tsx
|
| 70 |
|
| 71 |
+
const handleOtpChange = (index: number, value: string) => {
|
| 72 |
+
// Handle pasting multiple characters
|
| 73 |
+
if (value.length > 1) {
|
| 74 |
+
const pasted = value.slice(0, 6).split('');
|
| 75 |
+
const newOtp = [...otp];
|
| 76 |
+
pasted.forEach((char, i) => {
|
| 77 |
+
if (index + i < 6) newOtp[index + i] = char;
|
| 78 |
+
});
|
| 79 |
+
setOtp(newOtp);
|
| 80 |
+
setVerificationCode(newOtp.join(''));
|
| 81 |
+
|
| 82 |
+
// Focus the correct input after paste
|
| 83 |
+
const nextIndex = Math.min(index + pasted.length, 5);
|
| 84 |
+
document.getElementById(`otp-${nextIndex}`)?.focus();
|
| 85 |
+
return;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
const newOtp = [...otp];
|
| 89 |
+
newOtp[index] = value;
|
| 90 |
+
setOtp(newOtp);
|
| 91 |
+
setVerificationCode(newOtp.join(''));
|
| 92 |
+
|
| 93 |
+
// Move to next input if typing a character
|
| 94 |
+
if (value && index < 5) {
|
| 95 |
+
document.getElementById(`otp-${index + 1}`)?.focus();
|
| 96 |
+
}
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
const handleOtpKeyDown = (index: number, e: React.KeyboardEvent<HTMLInputElement>) => {
|
| 100 |
+
if (e.key === 'Backspace' && !otp[index] && index > 0) {
|
| 101 |
+
document.getElementById(`otp-${index - 1}`)?.focus();
|
| 102 |
+
}
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
const handleSubmit = async (e: React.FormEvent) => {
|
| 106 |
e.preventDefault();
|
| 107 |
setError("");
|
|
|
|
| 144 |
setError(detail[0]?.msg || "Validation error. Please check your inputs.");
|
| 145 |
} else if (typeof detail === 'string') {
|
| 146 |
setError(detail);
|
| 147 |
+
} else if (typeof err.response?.data === 'string') {
|
| 148 |
+
// This happens if the proxy (Vercel/HuggingFace) returns a 500/502 HTML error page
|
| 149 |
+
setError(`Server Error (${err.response.status}): The backend may be restarting or unavailable. Please wait a minute and try again.`);
|
| 150 |
} else {
|
| 151 |
setError("Server returned an unexpected error. Please try again.");
|
| 152 |
}
|
|
|
|
| 216 |
|
| 217 |
<form onSubmit={handleSubmit} className="space-y-4">
|
| 218 |
{mode === 'verify' ? (
|
| 219 |
+
<div className="flex justify-between gap-2 max-w-xs mx-auto mb-4">
|
| 220 |
+
{otp.map((digit, index) => (
|
| 221 |
+
<input
|
| 222 |
+
key={index}
|
| 223 |
+
id={`otp-${index}`}
|
| 224 |
+
type="text"
|
| 225 |
+
maxLength={6} // allow paste
|
| 226 |
+
value={digit}
|
| 227 |
+
onChange={(e) => handleOtpChange(index, e.target.value)}
|
| 228 |
+
onKeyDown={(e) => handleOtpKeyDown(index, e)}
|
| 229 |
+
className="w-12 h-14 bg-theme-text/5 border border-theme-border rounded-xl text-center text-xl text-[var(--theme-text)] focus:outline-none focus:border-theme-border/50 focus:bg-theme-text/10 transition-all font-mono"
|
| 230 |
+
/>
|
| 231 |
+
))}
|
| 232 |
</div>
|
| 233 |
) : (
|
| 234 |
<>
|