Files
lcbp3.np-dms.work/frontend/app/layout.jsx
2025-10-01 17:15:51 +07:00

112 lines
5.9 KiB
JavaScript
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// File: frontend/app/layout.jsx
import Link from "next/link";
import { redirect } from "next/navigation";
import { cookies, headers } from "next/headers";
// ถ้ามี lib rbac เดิมอยู่ให้ใช้ต่อได้
import { can } from "@/lib/rbac";
// แก้ title ให้ถูกสะกด
export const metadata = { title: "DMS | Protected" };
const API_BASE = (process.env.NEXT_PUBLIC_API_BASE || "").replace(/\/$/, "");
async function fetchSessionFromAPI() {
// ดึงคุกกี้จริงจากฝั่งเซิร์ฟเวอร์ แล้วส่งต่อให้ backend
const cookieHeader = cookies().toString(); // serialize ทั้งชุด
const hostHdr = headers().get("host");
const protoHdr = headers().get("x-forwarded-proto") || "https";
const res = await fetch(`${API_BASE}/api/auth/me`, {
method: "GET",
headers: {
Cookie: cookieHeader,
// เผื่อ backend ตรวจ origin/proto/host
"X-Forwarded-Host": hostHdr || "",
"X-Forwarded-Proto": protoHdr,
Accept: "application/json",
},
// server component ไม่ต้องใช้ credentials
cache: "no-store",
});
if (!res.ok) return null;
try {
const data = await res.json();
return data?.ok ? data : null;
} catch {
return null;
}
}
export default async function ProtectedLayout({ children }) {
const session = await fetchSessionFromAPI();
if (!session) {
// พยายามส่ง next path กลับไปที่ /login
redirect("/login?next=/dashboard");
}
const { user } = session;
return (
<section className="grid grid-cols-12 gap-6 p-4 mx-auto max-w-7xl">
<aside className="col-span-12 lg:col-span-3 xl:col-span-3">
<div className="p-4 border rounded-3xl bg-white/70">
<div className="mb-3 text-sm">RBAC: <b>{user.role}</b></div>
<nav className="space-y-2">
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/dashboard">แà¸à¸Šà¸šà¸­à¸£à¹Œà¸</Link>
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/drawings">Drawings</Link>
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/rfas">RFAs</Link>
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/transmittals">Transmittals</Link>
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/correspondences">Correspondences</Link>
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/contracts-volumes">Contracts & Volumes</Link>
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/reports">Reports</Link>
{can(user, "workflow:view") && (
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/workflow">Workflow (n8n)</Link>
)}
{can(user, "health:view") && (
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/health">Health</Link>
)}
{can(user, "users:manage") && (
<Link className="block px-4 py-2 rounded-xl bg-white/60 hover:bg-white" href="/users">ผูà¹à¹ƒà¸Šà¹/บà¸à¸šà¸²à¸</Link>
)}
</nav>
</div>
</aside>
<main className="col-span-12 space-y-6 lg:col-span-9 xl:col-span-9">
{/* System / Quick Actions */}
<div className="flex items-center gap-2">
<div className="flex-1 text-lg font-semibold">Document Management System â LCBP3 Phase 3</div>
{can(user, "admin:view") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/admin">Admin</a>
)}
{can(user, "users:manage") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/users">ผูà¹à¹ƒà¸Šà¹/บà¸à¸šà¸²à¸</a>
)}
{can(user, "health:view") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/health">Health</a>
)}
{can(user, "workflow:view") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/workflow">Workflow</a>
)}
{can(user, "rfa:create") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/rfas/new">+ RFA</a>
)}
{can(user, "drawing:upload") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/drawings/upload">+ Upload Drawing</a>
)}
{can(user, "transmittal:create") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/transmittals/new">+ Transmittal</a>
)}
{can(user, "correspondence:create") && (
<a className="px-3 py-2 text-white rounded-xl" style={{ background: "#0D5C75" }} href="/correspondences/new">+ หà¸à¸±à¸à¸ªà¸·à¸­à¸ªà¸·à¹ˆà¸­à¸ªà¸²à¸£</a>
)}
</div>
{children}
</main>
</section>
);
}