Files
Estacion-de-Documentos/frontend/app/subjects/[subjectId]/page.tsx
T
2026-05-19 14:21:56 -06:00

136 lines
5.9 KiB
TypeScript

"use client";
import Link from "next/link";
import { FormEvent, useEffect, useState } from "react";
import { api, Subject, Week } from "@/lib/api";
import { Shell } from "@/components/Shell";
import { Button, Card, Input, Label } from "@/components/ui";
export default function SubjectPage({ params }: { params: { subjectId: string } }) {
const subjectId = Number(params.subjectId);
const [subject, setSubject] = useState<Subject | null>(null);
const [weeks, setWeeks] = useState<Week[]>([]);
const [number, setNumber] = useState(1);
const [title, setTitle] = useState("");
const [editingWeek, setEditingWeek] = useState<Week | null>(null);
const [editNumber, setEditNumber] = useState(1);
const [editTitle, setEditTitle] = useState("");
const [error, setError] = useState("");
async function load() {
try {
const [subjectData, weekList] = await Promise.all([api.subject(subjectId), api.weeks(subjectId)]);
setSubject(subjectData);
setWeeks(weekList);
setNumber((weekList.at(-1)?.number || 0) + 1);
} catch (err) {
setError(err instanceof Error ? err.message : "No se pudo cargar la materia");
}
}
useEffect(() => { load(); }, [subjectId]);
async function createWeek(event: FormEvent) {
event.preventDefault();
try {
setError("");
await api.createWeek(subjectId, number, title);
setTitle("");
await load();
} catch (err) {
setError(err instanceof Error ? err.message : "No se pudo crear la semana");
}
}
function startEdit(week: Week) {
setEditingWeek(week);
setEditNumber(week.number);
setEditTitle(week.title || "");
setError("");
}
async function saveEdit(event: FormEvent) {
event.preventDefault();
if (!editingWeek) return;
try {
setError("");
await api.updateWeek(subjectId, editingWeek.number, editNumber, editTitle);
setEditingWeek(null);
await load();
} catch (err) {
setError(err instanceof Error ? err.message : "No se pudo editar la semana");
}
}
async function deleteWeek(week: Week) {
const confirmed = window.confirm(`Eliminar la semana ${week.number} tambien borrara sus archivos subidos, Markdown procesado y exports. Esta accion no se puede deshacer.`);
if (!confirmed) return;
try {
setError("");
await api.deleteWeek(subjectId, week.number);
if (editingWeek?.id === week.id) setEditingWeek(null);
await load();
} catch (err) {
setError(err instanceof Error ? err.message : "No se pudo eliminar la semana");
}
}
return (
<Shell>
<Link href="/" className="text-sm text-blue-300">Volver a materias</Link>
<div className="mt-4 grid gap-6 lg:grid-cols-[1fr_360px]">
<section>
<h1 className="text-4xl font-bold tracking-tight">{subject?.name || "Materia"}</h1>
<p className="mt-2 text-slate-400">Divide el conocimiento por semanas y sube fuentes a cada una.</p>
{error && <Card className="mt-4 border-red-500/30 bg-red-500/10 text-red-200">{error}</Card>}
<div className="mt-6 grid gap-4 md:grid-cols-2">
{weeks.map((week) => (
<Card key={week.id} className="transition hover:border-blue-400/40 hover:bg-blue-500/10">
<div className="text-2xl font-semibold">Semana {week.number}</div>
<div className="mt-2 text-slate-400">{week.title || "Sin titulo"}</div>
<div className="mt-5 flex flex-wrap gap-2 text-sm">
<Link className="rounded-lg bg-blue-600 px-3 py-2 font-medium text-white hover:bg-blue-500" href={`/subjects/${subjectId}/weeks/${week.number}`}>Abrir semana</Link>
<button className="rounded-lg border border-white/10 px-3 py-2 text-slate-200 hover:bg-white/10" type="button" onClick={() => startEdit(week)}>Editar</button>
<button className="rounded-lg border border-red-400/30 px-3 py-2 text-red-200 hover:bg-red-500/10" type="button" onClick={() => deleteWeek(week)}>Eliminar</button>
</div>
</Card>
))}
{weeks.length === 0 && <Card className="md:col-span-2">Todavia no hay semanas.</Card>}
</div>
</section>
<aside>
<Card>
{editingWeek ? (
<>
<h2 className="text-lg font-semibold">Editar semana</h2>
<p className="mt-1 text-sm text-slate-400">Cambia el numero o titulo. Si cambias el numero, se renombra la carpeta de la semana.</p>
<form className="mt-4 space-y-3" onSubmit={saveEdit}>
<Label>Numero</Label>
<Input type="number" min={1} value={editNumber} onChange={(event) => setEditNumber(Number(event.target.value))} />
<Label>Titulo</Label>
<Input value={editTitle} onChange={(event) => setEditTitle(event.target.value)} placeholder="Ej. Grupos y equipos" />
<div className="flex gap-2">
<Button className="flex-1">Guardar</Button>
<button className="flex-1 rounded-xl border border-white/10 px-4 py-2 hover:bg-white/10" type="button" onClick={() => setEditingWeek(null)}>Cancelar</button>
</div>
</form>
</>
) : (
<>
<h2 className="text-lg font-semibold">Nueva semana</h2>
<form className="mt-4 space-y-3" onSubmit={createWeek}>
<Label>Numero</Label>
<Input type="number" min={1} value={number} onChange={(event) => setNumber(Number(event.target.value))} />
<Label>Titulo opcional</Label>
<Input value={title} onChange={(event) => setTitle(event.target.value)} placeholder="Ej. Grupos y equipos" />
<Button className="w-full">Crear semana</Button>
</form>
</>
)}
</Card>
</aside>
</div>
</Shell>
);
}