2nd File: frontend/app/(auth)/login/page.jsx

This commit is contained in:
admin
2025-10-02 09:49:50 +07:00
parent 6fea909902
commit 03a8a3b864

View File

@@ -32,6 +32,24 @@ function LoginForm() {
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [err, setErr] = useState(""); const [err, setErr] = useState("");
// Helper function to verify session is ready after login
async function verifySessionIsReady() {
const MAX_RETRIES = 5;
const RETRY_DELAY = 300; // ms
for (let i = 0; i < MAX_RETRIES; i++) {
const me = await fetch(`${API_BASE}/api/auth/me`, {
method: "GET",
credentials: "include",
cache: "no-store",
}).then(r => r.ok ? r.json() : null).catch(() => null);
if (me?.ok) return true;
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
}
return false;
}
async function onSubmit(e) { async function onSubmit(e) {
e.preventDefault(); e.preventDefault();
setErr(""); setErr("");
@@ -68,16 +86,7 @@ function LoginForm() {
// ✅ ยืนยันว่าเซสชันพร้อมใช้งานก่อน (กัน redirect วน) // ✅ ยืนยันว่าเซสชันพร้อมใช้งานก่อน (กัน redirect วน)
// ✅ รอ session ให้พร้อมจริง (retry สูงสุด ~1.5s) // ✅ รอ session ให้พร้อมจริง (retry สูงสุด ~1.5s)
let me = null, ok = false; const ok = await verifySessionIsReady();
for (let i = 0; i < 5; i++) {
me = await fetch(`${API_BASE}/api/auth/me`, {
method: "GET",
credentials: "include",
cache: "no-store",
}).then(r => r.ok ? r.json() : null).catch(() => null);
if (me?.ok) { ok = true; break; }
await new Promise(r => setTimeout(r, 300)); // เว้นระยะ 300ms
}
if (!ok) { if (!ok) {
setErr("ล็อกอินสำเร็จ แต่ยังไม่เห็นเซสชันจากเซิร์ฟเวอร์ (ลองใหม่หรือตรวจคุกกี้)"); setErr("ล็อกอินสำเร็จ แต่ยังไม่เห็นเซสชันจากเซิร์ฟเวอร์ (ลองใหม่หรือตรวจคุกกี้)");
return; return;
@@ -175,12 +184,23 @@ function LoginPageSkeleton() {
<CardDescription className="text-sky-700">Document Management System LCBP3</CardDescription> <CardDescription className="text-sky-700">Document Management System LCBP3</CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="grid gap-4 animate-pulse"> {/* ✅ ปรับปรุง Skeleton ให้สมจริงขึ้น */}
<div className="h-10 rounded bg-slate-200"></div> <div className="grid gap-4">
<div className="h-10 rounded bg-slate-200"></div> <div className="grid gap-2">
<div className="h-10 rounded bg-slate-200"></div> <div className="w-20 h-4 rounded bg-slate-200 animate-pulse"></div>
<div className="h-10 rounded bg-slate-200 animate-pulse"></div>
</div>
<div className="grid gap-2">
<div className="w-16 h-4 rounded bg-slate-200 animate-pulse"></div>
<div className="h-10 rounded bg-slate-200 animate-pulse"></div>
</div>
<div className="h-10 mt-2 rounded bg-slate-200 animate-pulse"></div>
</div> </div>
</CardContent> </CardContent>
{/* ✅ เพิ่ม Skeleton สำหรับ Footer */}
<CardFooter className="flex justify-center">
<div className="w-48 h-4 rounded bg-slate-200 animate-pulse"></div>
</CardFooter>
</Card> </Card>
</div> </div>
); );