keeai / frontend /src /pages /Login.jsx
Seth0330's picture
Update frontend/src/pages/Login.jsx
4dcb2cf verified
// frontend/src/pages/Login.jsx
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import api from "../api/client";
export default function Login() {
const [step, setStep] = useState(1); // 1 = email, 2 = OTP
const [email, setEmail] = useState("student1@example.com");
const [otp, setOtp] = useState("");
const [serverOtp, setServerOtp] = useState("");
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState("");
const navigate = useNavigate();
async function handleRequestOtp(e) {
e.preventDefault();
setLoading(true);
setMessage("");
try {
const res = await api.post("/auth/request-otp", { email });
if (res.data?.debug_code) {
setServerOtp(res.data.debug_code);
setMessage(
`Test OTP (email not configured): ${res.data.debug_code}`
);
} else {
setMessage("OTP sent to your email address.");
}
setStep(2);
} catch (err) {
setMessage("Could not send OTP. Please try again.");
} finally {
setLoading(false);
}
}
async function handleVerifyOtp(e) {
e.preventDefault();
setLoading(true);
setMessage("");
try {
const res = await api.post("/auth/login", { email, otp });
const payload = {
email: res.data.email,
name: res.data.name,
};
// 🔑 IMPORTANT: this must match App.jsx + StudentDashboard
// Both use: localStorage.getItem("karateStudent")
localStorage.setItem("karateStudent", JSON.stringify(payload));
navigate("/student");
} catch (err) {
setMessage("Invalid or expired OTP. Please try again.");
} finally {
setLoading(false);
}
}
return (
<div className="min-h-screen bg-slate-50 text-slate-900 flex items-center justify-center px-4">
<div className="max-w-md w-full">
<div className="mb-8 text-center">
<h1 className="text-3xl font-semibold tracking-tight">
Arun Martial Arts Student Portal
</h1>
<p className="mt-2 text-sm text-slate-500">
Log in with your email. We’ll send you a one-time code.
</p>
</div>
<div className="bg-white shadow-xl rounded-2xl border border-slate-100 p-8">
<h2 className="text-lg font-semibold mb-1">
{step === 1 ? "Student Login" : "Enter OTP"}
</h2>
<p className="text-xs text-slate-500 mb-6">
{step === 1
? "Type your email address and we’ll send you a one-time code."
: "Check the code below (for testing) or your inbox, and confirm login."}
</p>
{step === 1 && (
<form className="space-y-4" onSubmit={handleRequestOtp}>
<div>
<label className="block text-xs font-medium text-slate-600 mb-1">
Email
</label>
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full inline-flex items-center justify-center rounded-lg bg-blue-600 text-white text-sm font-medium py-2.5 hover:bg-blue-700 disabled:opacity-60"
>
{loading ? "Sending…" : "Send OTP"}
</button>
</form>
)}
{step === 2 && (
<form className="space-y-4" onSubmit={handleVerifyOtp}>
<div>
<label className="block text-xs font-medium text-slate-600 mb-1">
Email
</label>
<input
type="email"
value={email}
disabled
className="w-full rounded-lg border border-slate-100 px-3 py-2 text-sm bg-slate-50 text-slate-500"
/>
</div>
<div>
<label className="block text-xs font-medium text-slate-600 mb-1">
One-time code
</label>
<input
type="text"
required
value={otp}
onChange={(e) => setOtp(e.target.value)}
className="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white tracking-[0.35em]"
placeholder="••••••"
/>
</div>
{serverOtp && (
<p className="text-[11px] text-amber-600 bg-amber-50 border border-amber-100 px-3 py-2 rounded-lg">
Sandbox hint: your OTP is{" "}
<span className="font-mono font-semibold">{serverOtp}</span>
</p>
)}
<button
type="submit"
disabled={loading}
className="w-full inline-flex items-center justify-center rounded-lg bg-blue-600 text-white text-sm font-medium py-2.5 hover:bg-blue-700 disabled:opacity-60"
>
{loading ? "Verifying…" : "Log in"}
</button>
</form>
)}
{message && (
<p className="mt-4 text-xs text-slate-600 whitespace-pre-line">
{message}
</p>
)}
</div>
</div>
</div>
);
}