Files
Estacion-de-Documentos/frontend/app/page.tsx
T
2026-05-17 10:14:14 -06:00

88 lines
3.7 KiB
TypeScript

"use client";
import Link from "next/link";
import { FormEvent, useEffect, useState } from "react";
import { api, SettingsStatus, Subject } from "@/lib/api";
import { Shell } from "@/components/Shell";
import { Button, Card, Input, Label } from "@/components/ui";
export default function DashboardPage() {
const [subjects, setSubjects] = useState<Subject[]>([]);
const [settings, setSettings] = useState<SettingsStatus | null>(null);
const [name, setName] = useState("");
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
async function load() {
setError("");
try {
const [subjectList, status] = await Promise.all([api.subjects(), api.settings()]);
setSubjects(subjectList);
setSettings(status);
} catch (err) {
setError(err instanceof Error ? err.message : "No se pudo conectar con la API");
} finally {
setLoading(false);
}
}
useEffect(() => { load(); }, []);
async function createSubject(event: FormEvent) {
event.preventDefault();
if (!name.trim()) return;
await api.createSubject(name.trim());
setName("");
await load();
}
return (
<Shell>
<div className="grid gap-6 lg:grid-cols-[1fr_360px]">
<section>
<div className="mb-6">
<p className="text-sm uppercase tracking-[0.25em] text-blue-300">Plataforma personal</p>
<h1 className="mt-2 text-4xl font-bold tracking-tight">Materias</h1>
<p className="mt-3 max-w-2xl text-slate-400">Organiza clases, PDFs, audios y videos por materia y semana. Todo termina en Markdown listo para ingesta en LLM.</p>
</div>
{error && <Card className="mb-4 border-red-500/30 bg-red-500/10 text-red-200">{error}</Card>}
{loading ? <Card>Cargando...</Card> : (
<div className="grid gap-4 md:grid-cols-2">
{subjects.map((subject) => (
<Link key={subject.id} href={`/subjects/${subject.id}`}>
<Card className="transition hover:border-blue-400/40 hover:bg-blue-500/10">
<div className="text-xl font-semibold">{subject.name}</div>
<div className="mt-2 text-sm text-slate-400">{subject.slug}</div>
<div className="mt-5 text-sm text-blue-300">Abrir materia</div>
</Card>
</Link>
))}
{subjects.length === 0 && <Card className="md:col-span-2">No hay materias todavia. Crea la primera para empezar.</Card>}
</div>
)}
</section>
<aside className="space-y-4">
<Card>
<h2 className="text-lg font-semibold">Nueva materia</h2>
<form className="mt-4 space-y-3" onSubmit={createSubject}>
<Label>Nombre</Label>
<Input value={name} onChange={(event) => setName(event.target.value)} placeholder="Ej. Comportamiento Organizacional" />
<Button className="w-full" disabled={!name.trim()}>Crear materia</Button>
</form>
</Card>
<Card>
<h2 className="text-lg font-semibold">Servicios</h2>
<div className="mt-4 space-y-3 text-sm">
<div className="flex justify-between"><span>Deepgram</span><span className={settings?.deepgram_configured ? "text-emerald-300" : "text-amber-300"}>{settings?.deepgram_configured ? "Configurado" : "Falta key"}</span></div>
<div className="flex justify-between"><span>Mistral OCR</span><span className={settings?.mistral_configured ? "text-emerald-300" : "text-amber-300"}>{settings?.mistral_configured ? "Configurado" : "Falta key"}</span></div>
</div>
</Card>
</aside>
</div>
</Shell>
);
}