commit wip
This commit is contained in:
@@ -43,7 +43,7 @@ export function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdd
|
|||||||
horas_teoricas: toNum(f.horas_teoricas),
|
horas_teoricas: toNum(f.horas_teoricas),
|
||||||
horas_practicas: toNum(f.horas_practicas),
|
horas_practicas: toNum(f.horas_practicas),
|
||||||
objetivos: toNull(f.objetivos),
|
objetivos: toNull(f.objetivos),
|
||||||
contenidos: {}, bibliografia: [], criterios_evaluacion: null,
|
contenidos: [], bibliografia: [], criterios_evaluacion: null,
|
||||||
}
|
}
|
||||||
const { error } = await supabase.from("asignaturas").insert([payload])
|
const { error } = await supabase.from("asignaturas").insert([payload])
|
||||||
setSaving(false)
|
setSaving(false)
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ export function DeletePlanButton({ planId, onDeleted }: { planId: string; onDele
|
|||||||
|
|
||||||
return confirm ? (
|
return confirm ? (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
<Button variant="outline" onClick={() => setConfirm(false)} disabled={loading}>Cancelar</Button>
|
||||||
<Button variant="destructive" onClick={handleDelete} disabled={loading}>
|
<Button variant="destructive" onClick={handleDelete} disabled={loading}>
|
||||||
{loading ? "Eliminando…" : "Confirmar eliminación"}
|
{loading ? "Eliminando…" : "Confirmar eliminación"}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" onClick={() => setConfirm(false)} disabled={loading}>Cancelar</Button>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Button variant="outline" onClick={() => setConfirm(true)}>
|
<Button variant="outline" onClick={() => setConfirm(true)}>
|
||||||
|
|||||||
33
src/components/planes/GenerarPdfButton.tsx
Normal file
33
src/components/planes/GenerarPdfButton.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { Download } from "lucide-react";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
|
||||||
|
export function DescargarPdfButton({planId, opcion}: {planId: string, opcion: "plan" | "asignaturas"}) {
|
||||||
|
return (
|
||||||
|
<Button variant="outline" className="flex items-center gap-2 " onClick={() => descargarPdf(planId, opcion)}>
|
||||||
|
Descargar {opcion === "plan" ? "Plan" : "Asignaturas"} PDF
|
||||||
|
<Download className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function descargarPdf(planId: string, opcion: "plan" | "asignaturas") {
|
||||||
|
// Lógica para generar y descargar el PDF del plan de estudios
|
||||||
|
try {
|
||||||
|
// Usa la variable de entorno para construir la URL completa
|
||||||
|
const pdfUrl = opcion === "plan"
|
||||||
|
? `${import.meta.env.VITE_BACK_ORIGIN}/api/planes/${planId}/descargar-pdf-plan`
|
||||||
|
: `${import.meta.env.VITE_BACK_ORIGIN}/api/planes/${planId}/descargar-pdf-asignaturas`;
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = pdfUrl;
|
||||||
|
link.download = opcion === "plan"
|
||||||
|
? `plan_estudios_${planId}.pdf`
|
||||||
|
: `asignaturas_plan_estudios_${planId}.pdf`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error al descargar el PDF:", error);
|
||||||
|
alert("Hubo un error al descargar el PDF. Por favor, inténtalo de nuevo.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,7 +135,7 @@ function Page() {
|
|||||||
{/* ===== Hero ===== */}
|
{/* ===== Hero ===== */}
|
||||||
<div className="relative overflow-hidden rounded-3xl border shadow-sm">
|
<div className="relative overflow-hidden rounded-3xl border shadow-sm">
|
||||||
<div className={`absolute inset-0 bg-gradient-to-br ${style.halo} via-white to-transparent`} />
|
<div className={`absolute inset-0 bg-gradient-to-br ${style.halo} via-white to-transparent`} />
|
||||||
<div className="relative p-6 flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
<div className="relative p-6 flex flex-col grid grid-cols-1 gap-4 md:flex-row md:items-center md:justify-between">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<div className="inline-flex items-center gap-2 text-xs text-neutral-600">
|
<div className="inline-flex items-center gap-2 text-xs text-neutral-600">
|
||||||
<Icons.BookOpen className="h-4 w-4" /> Asignatura
|
<Icons.BookOpen className="h-4 w-4" /> Asignatura
|
||||||
@@ -613,10 +613,10 @@ function BorrarAsignaturaButton({ asignatura_id, onDeleted }: { asignatura_id: s
|
|||||||
|
|
||||||
return confirm ? (
|
return confirm ? (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
<Button variant="outline" onClick={() => setConfirm(false)} disabled={loading}>Cancelar</Button>
|
||||||
<Button variant="destructive" onClick={handleDelete} disabled={loading}>
|
<Button variant="destructive" onClick={handleDelete} disabled={loading}>
|
||||||
{loading ? "Eliminando…" : "Confirmar eliminación"}
|
{loading ? "Eliminando…" : "Confirmar eliminación"}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" onClick={() => setConfirm(false)} disabled={loading}>Cancelar</Button>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Button variant="outline" onClick={() => setConfirm(true)}>
|
<Button variant="outline" onClick={() => setConfirm(true)}>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { AuroraButton } from "@/components/effect/aurora-button"
|
|||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||||
import { DeletePlanButton } from "@/components/planes/DeletePlan"
|
import { DeletePlanButton } from "@/components/planes/DeletePlan"
|
||||||
import { AddAsignaturaButton } from "@/components/planes/AddAsignaturaButton"
|
import { AddAsignaturaButton } from "@/components/planes/AddAsignaturaButton"
|
||||||
|
import { DescargarPdfButton } from "@/components/planes/GenerarPdfButton"
|
||||||
|
|
||||||
type LoaderData = { plan: PlanFull; asignaturas: AsignaturaLite[] }
|
type LoaderData = { plan: PlanFull; asignaturas: AsignaturaLite[] }
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@ function RouteComponent() {
|
|||||||
</nav>
|
</nav>
|
||||||
<Card ref={headerRef} className="relative overflow-hidden border shadow-sm">
|
<Card ref={headerRef} className="relative overflow-hidden border shadow-sm">
|
||||||
<div className="absolute inset-0 -z-0" style={accent} />
|
<div className="absolute inset-0 -z-0" style={accent} />
|
||||||
<CardHeader className="relative z-10 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
<CardHeader className="relative z-10 flex flex-col grid grid-cols-1 gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div className="flex items-center gap-3 min-w-0">
|
<div className="flex items-center gap-3 min-w-0">
|
||||||
<span className="hdr-icon inline-flex items-center justify-center rounded-2xl border px-3 py-2 bg-white/70"
|
<span className="hdr-icon inline-flex items-center justify-center rounded-2xl border px-3 py-2 bg-white/70"
|
||||||
style={{ borderColor: accent.borderColor as string }}>
|
style={{ borderColor: accent.borderColor as string }}>
|
||||||
@@ -99,11 +100,13 @@ function RouteComponent() {
|
|||||||
{plan.estado}
|
{plan.estado}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
<div className='flex gap-2'>
|
{/* <div className='flex gap-2'> */}
|
||||||
<EditPlanButton plan={plan} />
|
<EditPlanButton plan={plan} />
|
||||||
<AdjustAIButton plan={plan} />
|
<AdjustAIButton plan={plan} />
|
||||||
|
<DescargarPdfButton planId={plan.id} opcion="plan" />
|
||||||
|
<DescargarPdfButton planId={plan.id} opcion="asignaturas" />
|
||||||
<DeletePlanButton planId={plan.id} />
|
<DeletePlanButton planId={plan.id} />
|
||||||
</div>
|
{/* </div> */}
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent ref={statsRef}>
|
<CardContent ref={statsRef}>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createFileRoute, redirect } from "@tanstack/react-router"
|
import { createFileRoute, redirect, useRouter } from "@tanstack/react-router"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
@@ -27,6 +27,7 @@ function LoginComponent() {
|
|||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [error, setError] = useState("")
|
const [error, setError] = useState("")
|
||||||
const [showPassword, setShowPassword] = useState(false)
|
const [showPassword, setShowPassword] = useState(false)
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -35,7 +36,7 @@ function LoginComponent() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await auth.login(email, password)
|
await auth.login(email, password)
|
||||||
window.location.href = redirect
|
router.navigate({ to: redirect})
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setError(err.message || "No fue posible iniciar sesión")
|
setError(err.message || "No fue posible iniciar sesión")
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user