feat: frontend alumnos sam-pruebas (RUT+clave, rendir y mis resultados)

This commit is contained in:
Nurfog committed 2026-09-28 10:58:45 -03:00
commit e6d283e184
26 files changed
+2555

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
"use client";
import { createContext, useContext, useEffect, useState } from "react";
export interface AlumnoUser {
idAlumno: string;
nombres: string;
apPaterno: string;
apMaterno?: string;
email: string;
/** De qué tabla viene: SAM (sige_sam_v3.alumnos) o EMPRESA (sige_sam_empresa.alumnos). */
origen: string;
}
interface SessionCtx {
user: AlumnoUser | null;
loading: boolean;
login: (idAlumno: string, password: string) => Promise<void>;
logout: () => Promise<void>;
}
const Ctx = createContext<SessionCtx | null>(null);
export function SessionProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<AlumnoUser | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/auth/me")
.then((r) => (r.ok ? r.json() : null))
.then((d) => setUser(d?.user ?? null))
.catch(() => setUser(null))
.finally(() => setLoading(false));
}, []);
async function login(idAlumno: string, password: string) {
const r = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ idAlumno, password })
});
const d = await r.json().catch(() => null);
if (!r.ok || !d?.success) throw new Error(d?.message || "Credenciales inválidas");
setUser(d.user);
}
async function logout() {
await fetch("/api/auth/logout", { method: "POST" });
setUser(null);
}
return <Ctx.Provider value={{ user, loading, login, logout }}>{children}</Ctx.Provider>;
}
export function useSession() {
const ctx = useContext(Ctx);
if (!ctx) throw new Error("useSession fuera de SessionProvider");
return ctx;
}