feat(01-02): login page UI, logout flow, seed script, and auth unit tests

- src/app/(auth)/layout.tsx: centered auth layout for login page
- src/app/(auth)/login/page.tsx: login form with error/loading states, sign up link
- src/components/providers.tsx: SessionProvider wrapper for client-side session
- src/components/layout/header.tsx: authenticated header with Sign out button
- src/app/(dashboard)/layout.tsx: dashboard layout wrapping Header component
- src/app/(dashboard)/dashboard/page.tsx: basic dashboard page post-login
- src/app/layout.tsx: wrap root with SessionProvider via Providers component
- prisma/seed.ts: idempotent seed for Demo ISP tenant + admin + super-admin users
- package.json: add db:seed script and prisma.seed config, add tsx devDep
- src/lib/__tests__/auth.test.ts: 8 unit tests for authOptions callbacks
This commit is contained in:
kevin-asprec
2026-03-04 18:42:53 +08:00
parent 43761d94ee
commit 3c37cb1866
10 changed files with 895 additions and 4 deletions

View File

@@ -0,0 +1,31 @@
import { getCurrentUser } from "@/lib/auth";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const user = await getCurrentUser();
if (!user) {
redirect("/login");
}
return (
<div>
<h1 className="text-2xl font-bold text-gray-900 mb-2">Dashboard</h1>
<p className="text-gray-600">
Welcome back, {user.firstName} {user.lastName}
</p>
<div className="mt-6 p-4 bg-white rounded-lg border border-gray-200 inline-block">
<p className="text-sm text-gray-500">Signed in as</p>
<p className="font-medium text-gray-900">{user.email}</p>
{user.tenantId && (
<p className="text-sm text-gray-500 mt-1">Tenant: {user.tenantId}</p>
)}
{user.isSuperAdmin && (
<p className="text-sm text-blue-600 mt-1 font-medium">
Super Admin
</p>
)}
</div>
</div>
);
}