feat: implement structured grading system with predefined assessment types

- Add structured grading policy with predefined types (Continuous Assessment, Midterm, Final Test, Exam)
- Replace free-text category input with combobox selection in Grading Policy page
- Update Lesson Editor to use dropdown selector for grading category assignment
- Fix create_grading_category handler to capture organization context
- Fix update_course handler to set audit context in database transaction
- Implement getImageUrl helper for proper asset path resolution
- Add unoptimized prop to organization logo images to bypass Next.js optimization
- Add database migrations for organization_id in content tables
- Seed default tutorial courses for Admin, Instructor, and Student roles
- Fix audit log constraints and content schema issues
This commit is contained in:
2026-01-12 00:52:26 -03:00
parent 3ddcaaaf15
commit 942780db1c
19 changed files with 476 additions and 92 deletions
+4 -4
View File
@@ -3,10 +3,12 @@
import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { lmsApi } from "@/lib/api";
import { useAuth } from "@/context/AuthContext";
import { GraduationCap, Lock, Mail, User, Building2 } from "lucide-react";
export default function ExperienceLoginPage() {
const router = useRouter();
const { login } = useAuth();
const [isLogin, setIsLogin] = useState(true);
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
@@ -31,8 +33,7 @@ export default function ExperienceLoginPage() {
return;
}
localStorage.setItem("experience_token", response.token);
localStorage.setItem("experience_user", JSON.stringify(response.user));
login(response.user, response.token);
router.push("/");
} else {
const response = await lmsApi.register({
@@ -42,8 +43,7 @@ export default function ExperienceLoginPage() {
organization_name: organizationName,
});
localStorage.setItem("experience_token", response.token);
localStorage.setItem("experience_user", JSON.stringify(response.user));
login(response.user, response.token);
router.push("/");
}
} catch (err) {
+12 -9
View File
@@ -4,6 +4,7 @@ import "./globals.css";
import Link from "next/link";
import { AuthProvider } from "@/context/AuthContext";
import { BrandingProvider } from "@/context/BrandingContext";
import AuthGuard from "@/components/AuthGuard";
const inter = Inter({ subsets: ["latin"] });
@@ -24,15 +25,17 @@ export default function RootLayout({
<body className={`${inter.className} bg-[#050505] text-[#e5e5e5] min-h-screen flex flex-col`}>
<BrandingProvider>
<AuthProvider>
<AppHeader />
<main className="flex-1">
{children}
</main>
<footer className="py-12 px-6 border-t border-white/5 text-center bg-black/20">
<p className="text-[10px] font-black uppercase tracking-[0.2em] text-gray-600">
Powered by OpenCCB &copy; 2023. Advanced Agentic Coding.
</p>
</footer>
<AuthGuard>
<AppHeader />
<main className="flex-1">
{children}
</main>
<footer className="py-12 px-6 border-t border-white/5 text-center bg-black/20">
<p className="text-[10px] font-black uppercase tracking-[0.2em] text-gray-600">
Powered by OpenCCB &copy; 2023. Advanced Agentic Coding.
</p>
</footer>
</AuthGuard>
</AuthProvider>
</BrandingProvider>
</body>