feat: add AI-generated study plan creation dialog and API integration

- Implemented CreatePlanDialog component for generating study plans using AI.
- Integrated postAPI function for handling API requests.
- Updated planes.tsx to include AI plan generation logic.
- Modified usuarios.tsx to enable email confirmation for new users.
- Added Switch component for UI consistency.
- Created api.ts for centralized API handling.
- Developed carreras.tsx for managing career data with filtering and CRUD operations.
- Added CarreraFormDialog and CarreraDetailDialog for creating and editing career details.
- Implemented CriterioFormDialog for adding criteria to careers.
This commit is contained in:
2025-08-25 09:29:22 -06:00
parent ca3fed69b2
commit 012a5a58b0
12 changed files with 1590 additions and 246 deletions

View File

@@ -26,6 +26,8 @@ import {
KeySquare,
IdCard,
Users2Icon,
FileAxis3D,
FolderCheck,
} from "lucide-react"
import { useSupabaseAuth } from "@/auth/supabase"
@@ -43,6 +45,7 @@ const nav = [
{ to: "/asignaturas", label: "Asignaturas", icon: FileText },
{ to: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
{ to: "/usuarios", label: "Usuarios", icon: Users2Icon },
{ to: "/archivos", label: "Archivos de referencia", icon: FileAxis3D },
] as const
function getInitials(name?: string) {
@@ -60,12 +63,13 @@ function useUserDisplay() {
const fullName = [titulo, nombre, apellidos].filter(Boolean).join(" ")
const shortName = [titulo, nombre, apellidos.split(" ")[0] ?? ""].filter(Boolean).join(" ")
const role = claims?.role ?? ""
return {
fullName,
shortName,
clave,
email: user?.email,
avatar: claims?.avatar ?? null,
avatar: claims?.avatar ?? null,
initials: getInitials([nombre, apellidos].filter(Boolean).join(" ")),
role,
isAdmin: Boolean(claims?.claims_admin),
@@ -90,7 +94,7 @@ function Layout() {
</Button>
</SheetTrigger>
<SheetContent side="left" className="p-0">
<Sidebar onNavigate={() => {}} />
<Sidebar onNavigate={() => { }} />
</SheetContent>
</Sheet>
@@ -145,6 +149,9 @@ function Sidebar({ onNavigate }: { onNavigate?: () => void }) {
const { claims } = useSupabaseAuth()
const isAdmin = Boolean(claims?.claims_admin)
const canSeeCarreras = ["jefe_carrera", 'vicerrectoria', 'secretario_academico', 'lci'].includes(claims?.role ?? '')
return (
<div className="h-full">
<div className="flex items-center gap-2 p-4 md:hidden">
@@ -171,6 +178,18 @@ function Sidebar({ onNavigate }: { onNavigate?: () => void }) {
</Link>
))}
{canSeeCarreras && (
<Link
to="/carreras"
activeOptions={{ exact: true }}
activeProps={{ className: "bg-primary/10 text-foreground" }}
className="group inline-flex items-center gap-3 rounded-xl px-3 py-2 text-sm text-muted-foreground hover:bg-primary/10 hover:text-foreground"
>
<FolderCheck className="h-4 w-4" />
<span className="truncate">Carreras</span>
</Link>
)}
{isAdmin && (
<Link
to="/facultades"