feat: implementasi Kodeva - sistem manajemen kursus coding
Fitur lengkap: - Auth JWT + RBAC (Admin/Teacher) + halaman login - Shell 3 kolom (left nav, topbar, right rail dashboard) - CRUD siswa + follow up kanban + status calon/student/ex - Dashboard: siswa aktif, kehadiran, bar sumber lead, perlu follow up - Pembayaran prorata per pertemuan (cash/transfer/qris) - Kelas, enrollment, generate sesi, kehadiran bulk - Jurnal aktivitas + upload multi-foto - Raport + placement test (tampil di detail siswa) - Pengaturan & seed data contoh Stack: Next.js 16, TypeScript, Tailwind v4, Prisma (SQLite), Recharts, Zod
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
"use server";
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { loginSchema } from "@/lib/validators";
|
||||
import { clearSessionCookie, setSessionCookie } from "@/lib/auth";
|
||||
|
||||
export type LoginState = { error?: string } | undefined;
|
||||
|
||||
export async function loginAction(_prev: LoginState, formData: FormData): Promise<LoginState> {
|
||||
const parsed = loginSchema.safeParse({
|
||||
email: formData.get("email"),
|
||||
password: formData.get("password"),
|
||||
});
|
||||
if (!parsed.success) return { error: "Email atau password tidak valid." };
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email: parsed.data.email } });
|
||||
if (!user || !user.isActive || !bcrypt.compareSync(parsed.data.password, user.passwordHash)) {
|
||||
return { error: "Email atau password salah." };
|
||||
}
|
||||
|
||||
await setSessionCookie({
|
||||
userId: user.id,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
role: user.role === "ADMIN" ? "ADMIN" : "TEACHER",
|
||||
});
|
||||
redirect("/dashboard");
|
||||
}
|
||||
|
||||
export async function logoutAction() {
|
||||
await clearSessionCookie();
|
||||
redirect("/login");
|
||||
}
|
||||
Reference in New Issue
Block a user