feat: implement DetailDialog component for PDF viewing and downloading; refactor API calls to use environment variables

This commit is contained in:
2025-09-04 07:38:58 -06:00
parent 1808ce6f81
commit 2367baa538
10 changed files with 195 additions and 80 deletions

View File

@@ -13,21 +13,9 @@ import {
} from "@/components/ui/dialog"
import { Textarea } from "@/components/ui/textarea"
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from "@/components/ui/select"
import { DetailDialog } from "@/components/archivos/DetailDialog"
type RefRow = {
fine_tuning_referencias_id: string
titulo_archivo: string | null
descripcion: string | null
contenido_archivo: any | null
tipo_contenido: string | null
fecha_subida: string | null
procesado: boolean | null
tags: string[] | null
fuente_autoridad: string | null
interno: boolean | null
instrucciones: string
created_by: string | null
}
import type { RefRow } from "@/types/RefRow"
export const Route = createFileRoute("/_authenticated/archivos")({
component: RouteComponent,
@@ -200,63 +188,6 @@ function RouteComponent() {
)
}
/* ========= Detalle ========= */
function DetailDialog({ row, onClose }: { row: RefRow | null; onClose: () => void }) {
return (
<Dialog open={!!row} onOpenChange={(o) => !o && onClose()}>
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle className="font-mono" >{row?.titulo_archivo ?? "(Sin título)"}</DialogTitle>
<DialogDescription>
{row?.descripcion || "Sin descripción"}
</DialogDescription>
</DialogHeader>
{row && (
<div className="space-y-3">
<div className="text-xs flex flex-wrap gap-2">
<Badge variant="outline">{row.tipo_contenido ?? "—"}</Badge>
<Badge variant="outline">{row.interno ? "Interno" : "Externo"}</Badge>
<Badge variant="outline">{row.procesado ? "Procesado" : "Pendiente"}</Badge>
{row.fuente_autoridad && <Badge variant="outline">{row.fuente_autoridad}</Badge>}
{row.fecha_subida && (
<span className="inline-flex items-center gap-1">
<Icons.CalendarClock className="w-3 h-3" />
{new Date(row.fecha_subida).toLocaleString()}
</span>
)}
</div>
{row.tags && row.tags.length > 0 && (
<div className="text-xs text-neutral-600">
<span className="font-medium">Tags: </span>{row.tags.join(", ")}
</div>
)}
<div>
<Label className="text-xs text-neutral-600">Instrucciones</Label>
<div className="mt-1 rounded-xl border bg-white/60 p-3 text-sm whitespace-pre-wrap">
{row.instrucciones || "—"}
</div>
</div>
<div>
<Label className="text-xs text-neutral-600">Contenido (JSON)</Label>
<pre className="mt-1 rounded-xl border bg-neutral-950 text-neutral-100 p-3 max-h-[360px] overflow-auto text-xs">
{JSON.stringify(row.contenido_archivo ?? {}, null, 2)}
</pre>
</div>
</div>
)}
<DialogFooter>
<Button onClick={onClose}>Cerrar</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
/* ========= Subida ========= */
function UploadDialog({
open, onOpenChange, onDone,
@@ -284,7 +215,7 @@ function UploadDialog({
try {
const fileBase64 = await toBase64(file)
// Enviamos al motor (inserta en la tabla si insert=true)
const res = await fetch("https://genesis-engine.apps.lci.ulsa.mx/api/upload/documento", {
const res = await fetch(`${import.meta.env.VITE_BACK_ORIGIN}/api/upload/documento`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({

View File

@@ -504,7 +504,7 @@ function MejorarAIButton({ asignaturaId, onApply }: {
async function apply() {
setLoading(true)
try {
const res = await fetch("https://genesis-engine.apps.lci.ulsa.mx/api/mejorar/asignatura", {
const res = await fetch(`${import.meta.env.VITE_BACK_ORIGIN}/api/mejorar/asignatura`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ asignatura_id: asignaturaId, prompt, insert }),

View File

@@ -182,7 +182,7 @@ function Page() {
Plan
</div>
<DialogHeader className="p-0">
<DialogTitle className="font-mono" className="truncate text-xl sm:text-2xl">{planNombre}</DialogTitle>
<DialogTitle className="font-mono truncate text-xl sm:text-2xl">{planNombre}</DialogTitle>
</DialogHeader>
<div className="mt-2 flex flex-wrap items-center gap-2 text-xs">
<KpiChip icon={Icons.BookOpen} label="Asignaturas" value={kpis.total} />

View File

@@ -270,7 +270,7 @@ function AdjustAIButton({ plan }: { plan: PlanFull }) {
async function apply() {
setLoading(true)
await fetch('https://genesis-engine.apps.lci.ulsa.mx/api/mejorar/plan', {
await fetch(`${import.meta.env.VITE_BACK_ORIGIN}/api/mejorar/plan`, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt, plan_id: plan.id }),
}).catch(() => { })
@@ -462,7 +462,7 @@ function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdded?: ()
if (!canIA) return
setSaving(true)
try {
const res = await fetch("https://genesis-engine.apps.lci.ulsa.mx/api/generar/asignatura", {
const res = await fetch(`${import.meta.env.VITE_BACK_ORIGIN}/api/generar/asignatura`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ planEstudiosId: planId, prompt: iaPrompt, semestre: iaSemestre.trim() ? Number(iaSemestre) : undefined, insert: true }),