2 Commits

Author SHA1 Message Date
8da08b6bf1 La pantalla se volvía negra al abrir el dialogo de eliminar carrera
La razón es que se rendereaba un dialogo de borrado por carrera, pero al abrir uno se abrian los demás también
2025-10-24 13:01:33 -06:00
1fe8f2b6a8 Se corrigen bugs sobre crear carreras, filtrado y que aparezcan las materias cuando se crean 2025-10-24 12:36:39 -06:00
4 changed files with 42 additions and 9 deletions

View File

@@ -30,7 +30,7 @@ export function useDeleteCarreraDialog(carreraId: string, onDeleted?: () => void
const dialog = ( const dialog = (
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogContent> <DialogContent className="bg-white">
<DialogHeader> <DialogHeader>
<DialogTitle className="font-mono" >¿Eliminar carrera?</DialogTitle> <DialogTitle className="font-mono" >¿Eliminar carrera?</DialogTitle>
<DialogDescription> <DialogDescription>

View File

@@ -11,9 +11,11 @@ import { supabase, useSupabaseAuth } from "@/auth/supabase"
import { Field } from "./Field" import { Field } from "./Field"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs" import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"
import { asignaturaKeys } from "./planQueries" import { asignaturaKeys } from "./planQueries"
import { useRouter } from "@tanstack/react-router"
export function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdded?: () => void }) { export function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdded?: () => void }) {
const qc = useQueryClient() const qc = useQueryClient()
const router = useRouter()
const supabaseAuth = useSupabaseAuth() const supabaseAuth = useSupabaseAuth()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
@@ -45,7 +47,13 @@ export function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdd
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,data } = await supabase.from("asignaturas").insert([payload]).select().single()
console.log(data);
router.invalidate()
router.navigate({
to: "/asignatura/$asignaturaId",
params: { asignaturaId: data.id },
})
setSaving(false) setSaving(false)
if (error) { alert(error.message); return } if (error) { alert(error.message); return }
setOpen(false) setOpen(false)
@@ -64,8 +72,17 @@ export function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdd
body: JSON.stringify({ planEstudiosId: planId, prompt: iaPrompt, semestre: iaSemestre.trim() ? Number(iaSemestre) : undefined, insert: true, uuid: supabaseAuth.user?.id }), body: JSON.stringify({ planEstudiosId: planId, prompt: iaPrompt, semestre: iaSemestre.trim() ? Number(iaSemestre) : undefined, insert: true, uuid: supabaseAuth.user?.id }),
}) })
if (!res.ok) throw new Error(await res.text()) if (!res.ok) throw new Error(await res.text())
const data = await res.json()
console.log("Asignatura generada:", data)
const asignaturaId = data.asignaturaId || data.insertResult?.id
if (!asignaturaId) throw new Error("No se recibió el ID de la asignatura generada")
confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } }) confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } })
setOpen(false) setOpen(false)
router.invalidate()
router.navigate({
to: "/asignatura/$asignaturaId",
params: { asignaturaId },
})
onAdded?.() onAdded?.()
// qc.invalidateQueries({ queryKey: asignaturaKeys.preview(planId) }) // qc.invalidateQueries({ queryKey: asignaturaKeys.preview(planId) })
// qc.invalidateQueries({ queryKey: asignaturaKeys.count(planId) }) // qc.invalidateQueries({ queryKey: asignaturaKeys.count(planId) })

View File

@@ -126,6 +126,17 @@ function RouteComponent() {
const [detail, setDetail] = useState<CarreraRow | null>(null) const [detail, setDetail] = useState<CarreraRow | null>(null)
const [editCarrera, setEditCarrera] = useState<CarreraRow | null>(null) const [editCarrera, setEditCarrera] = useState<CarreraRow | null>(null)
const [createOpen, setCreateOpen] = useState(false) const [createOpen, setCreateOpen] = useState(false)
const [deleteTarget, setDeleteTarget] = useState<CarreraRow | null>(null)
// ✅ Se declara UNA SOLA VEZ
const { setOpen: setDeleteOpen, dialog: deleteDialog } = useDeleteCarreraDialog(
deleteTarget?.id ?? "",
async () => {
await qc.invalidateQueries({ queryKey: carrerasKeys.root })
router.invalidate()
// setDeleteTarget(null)
}
)
const filtered = useMemo(() => { const filtered = useMemo(() => {
const term = q.trim().toLowerCase() const term = q.trim().toLowerCase()
@@ -198,10 +209,7 @@ function RouteComponent() {
const border = tint(fac?.color, 0.28) const border = tint(fac?.color, 0.28)
const chip = tint(fac?.color, 0.1) const chip = tint(fac?.color, 0.1)
const IconComp = (fac?.icon && (Icons as any)[fac.icon]) || Icons.Building2 const IconComp = (fac?.icon && (Icons as any)[fac.icon]) || Icons.Building2
const { setOpen: setDeleteOpen, dialog: deleteDialog } = useDeleteCarreraDialog(c.id, async () => {
await qc.invalidateQueries({ queryKey: carrerasKeys.root })
router.invalidate()
})
return ( return (
<ContextMenu key={c.id}> <ContextMenu key={c.id}>
<ContextMenuTrigger onClick={(e) => openContextMenu(e)}> <ContextMenuTrigger onClick={(e) => openContextMenu(e)}>
@@ -233,11 +241,14 @@ function RouteComponent() {
<ContextMenuItem onClick={() => setEditCarrera(c)}> <ContextMenuItem onClick={() => setEditCarrera(c)}>
<Icons.Pencil className="w-4 h-4 mr-2" /> Editar <Icons.Pencil className="w-4 h-4 mr-2" /> Editar
</ContextMenuItem> </ContextMenuItem>
<ContextMenuItem onClick={() => setDeleteOpen(true)}> <ContextMenuItem onClick={() => {
setDeleteTarget(c)
setDeleteOpen(true)
}}>
<Icons.Trash className="w-4 h-4 mr-2" /> Eliminar <Icons.Trash className="w-4 h-4 mr-2" /> Eliminar
</ContextMenuItem> </ContextMenuItem>
</ContextMenuContent> </ContextMenuContent>
{deleteDialog}
</ContextMenu> </ContextMenu>
) )
})} })}
@@ -247,6 +258,8 @@ function RouteComponent() {
</CardContent> </CardContent>
</Card> </Card>
{deleteDialog}
{/* Crear / Editar */} {/* Crear / Editar */}
<CarreraFormDialog <CarreraFormDialog
open={createOpen} open={createOpen}

View File

@@ -49,7 +49,10 @@ export const Route = createFileRoute("/_authenticated/plan/$planId")({
// ...existing code... // ...existing code...
function RouteComponent() { function RouteComponent() {
const qc = useQueryClient() const qc = useQueryClient()
const { plan, asignaturas: asignaturasPreview } = Route.useLoaderData() as LoaderData //const { plan, asignaturas: asignaturasPreview } = Route.useLoaderData() as LoaderData
const { plan } = Route.useLoaderData() as LoaderData
const { data: asignaturasPreview } = useSuspenseQuery(asignaturasPreviewOptions(plan.id))
const auth = useSupabaseAuth() const auth = useSupabaseAuth()
const asignaturasCount = asignaturasPreview.length const asignaturasCount = asignaturasPreview.length