// File: frontend/app/(auth)/login/page.jsx "use client"; // ✅ ปรับให้ตรง backend: ใช้ Bearer token (ไม่ใช้ cookie) // - เรียก POST /api/auth/login → รับ { token, refresh_token, user } // - เก็บ token/refresh_token ใน localStorage (หรือ sessionStorage ถ้าไม่ติ๊กจำไว้) // - ไม่ใช้ credentials: "include" อีกต่อไป // - เอา RootLayout/metadata ออก เพราะไฟล์เพจเป็น client component // - เพิ่มการอ่าน NEXT_PUBLIC_API_BASE และ error handling ให้ตรงกับ backend // - เพิ่มโหมดดีบัก เปิดด้วย NEXT_PUBLIC_DEBUG_AUTH=1 import { useState, useMemo, Suspense } from "react"; import { useSearchParams, useRouter } from "next/navigation"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Alert, AlertDescription } from "@/components/ui/alert"; const API_BASE = process.env.NEXT_PUBLIC_API_BASE?.replace(/\/$/, "") || ""; const DEBUG = String(process.env.NEXT_PUBLIC_DEBUG_AUTH || "").trim() !== "" && process.env.NEXT_PUBLIC_DEBUG_AUTH !== "0" && process.env.NEXT_PUBLIC_DEBUG_AUTH !== "false"; function dlog(...args) { if (DEBUG && typeof window !== "undefined") { console.debug("[login]", ...args); } } function LoginForm() { const router = useRouter(); const searchParams = useSearchParams(); const nextPath = useMemo( () => searchParams.get("next") || "/dashboard", [searchParams] ); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [showPw, setShowPw] = useState(false); const [remember, setRemember] = useState(false); const [submitting, setSubmitting] = useState(false); const [err, setErr] = useState(""); async function onSubmit(e) { e.preventDefault(); setErr(""); if (!username.trim() || !password) { setErr("กรอกชื่อผู้ใช้และรหัสผ่านให้ครบ"); return; } try { setSubmitting(true); // ── DEBUG: ค่าเบื้องต้น dlog("API_BASE =", API_BASE || "(empty → จะเรียก path relative)"); dlog("nextPath =", nextPath); dlog("remember =", remember); dlog("payload =", { username: "[hidden]", password: "[hidden]" }); const res = await fetch(`${API_BASE}/api/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username, password }), cache: "no-store", }); dlog("response.status =", res.status); dlog("response.headers.content-type =", res.headers.get("content-type")); let data = {}; try { data = await res.json(); } catch (e) { dlog("response.json() error =", e); } dlog("response.body =", data); if (!res.ok) { const msg = data?.error === "INVALID_CREDENTIALS" ? "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง" : data?.error || `เข้าสู่ระบบไม่สำเร็จ (HTTP ${res.status})`; dlog("login FAILED →", msg); setErr(msg); return; } if (!data?.token) { dlog("login FAILED → data.token not found"); setErr("รูปแบบข้อมูลตอบกลับไม่ถูกต้อง (ไม่มี token)"); return; } // ✅ เก็บ token ตามโหมดจำไว้/ไม่จำ const storage = remember ? window.localStorage : window.sessionStorage; storage.setItem("dms.token", data.token); storage.setItem("dms.refresh_token", data.refresh_token); storage.setItem("dms.user", JSON.stringify(data.user || {})); dlog("token stored in", remember ? "localStorage" : "sessionStorage"); // (ออปชัน) เผยแพร่ event ให้แท็บอื่นทราบ try { window.dispatchEvent( new StorageEvent("storage", { key: "dms.auth", newValue: "login" }) ); } catch {} dlog("navigating →", nextPath); router.replace(nextPath); } catch (e) { dlog("exception =", e); setErr("เชื่อมต่อเซิร์ฟเวอร์ไม่ได้ กรุณาลองใหม่"); } finally { setSubmitting(false); dlog("done"); } } return (
เข้าสู่ระบบ Document Management System • LCBP3 {err ? ( {err} ) : null}
setUsername(e.target.value)} placeholder="เช่น superadmin" disabled={submitting} />
setPassword(e.target.value)} placeholder="••••••••" disabled={submitting} className="pr-10" />
ลืมรหัสผ่าน?
{DEBUG ? (

DEBUG: NEXT_PUBLIC_API_BASE = {API_BASE || "(empty)"}

) : null}
© {new Date().getFullYear()} np-dms.work
); } export default function LoginPage() { return ( }> ); } /** Loading skeleton */ function LoginPageSkeleton() { return (
เข้าสู่ระบบ Document Management System • LCBP3
); } /** Spinner แบบไม่พึ่งไลบรารีเสริม */ function Spinner() { return ( ); }