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:
Amadea
2026-09-18 19:24:59 +07:00
commit 61ce9d7926
86 changed files with 13392 additions and 0 deletions
+35
View File
@@ -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");
}