Compare commits
2 Commits
e03d5f5e36
...
c49c0bbc0a
| Author | SHA1 | Date | |
|---|---|---|---|
| c49c0bbc0a | |||
| 101758da24 |
@@ -50,8 +50,6 @@ export function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdd
|
|||||||
if (error) { alert(error.message); return }
|
if (error) { alert(error.message); return }
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
onAdded?.()
|
onAdded?.()
|
||||||
qc.invalidateQueries({ queryKey: asignaturaKeys.preview(planId) })
|
|
||||||
qc.invalidateQueries({ queryKey: asignaturaKeys.count(planId) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createWithAI() {
|
async function createWithAI() {
|
||||||
@@ -69,8 +67,8 @@ export function AddAsignaturaButton({ planId, onAdded }: { planId: string; onAdd
|
|||||||
confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } })
|
confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } })
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
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) })
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
alert(e?.message ?? "Error al generar la asignatura")
|
alert(e?.message ?? "Error al generar la asignatura")
|
||||||
} finally { setSaving(false) }
|
} finally { setSaving(false) }
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export function CreatePlanDialog({ open, onOpenChange }: { open: boolean; onOpen
|
|||||||
try {
|
try {
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from("documentos")
|
.from("documentos")
|
||||||
.select("documentos_id, titulo_archivo, s3_file_path, fecha_subida, tags")
|
.select("documentos_id, titulo_archivo, fecha_subida, tags")
|
||||||
.ilike("titulo_archivo", `%${debouncedSearchTerm}%`)
|
.ilike("titulo_archivo", `%${debouncedSearchTerm}%`)
|
||||||
.range((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage - 1);
|
.range((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage - 1);
|
||||||
|
|
||||||
@@ -261,8 +261,7 @@ export function CreatePlanDialog({ open, onOpenChange }: { open: boolean; onOpen
|
|||||||
const ext = fileExt(file.titulo);
|
const ext = fileExt(file.titulo);
|
||||||
const selected = isSelected(file.s3_file_path);
|
const selected = isSelected(file.s3_file_path);
|
||||||
return (
|
return (
|
||||||
<button
|
<div
|
||||||
type="button"
|
|
||||||
key={file.id}
|
key={file.id}
|
||||||
role="gridcell"
|
role="gridcell"
|
||||||
aria-selected={selected}
|
aria-selected={selected}
|
||||||
@@ -353,7 +352,7 @@ export function CreatePlanDialog({ open, onOpenChange }: { open: boolean; onOpen
|
|||||||
<span className="truncate">{ext.toUpperCase()}</span>
|
<span className="truncate">{ext.toUpperCase()}</span>
|
||||||
{selected ? <span className="font-medium">Seleccionado</span> : <span className="opacity-60">Click para seleccionar</span>}
|
{selected ? <span className="font-medium">Seleccionado</span> : <span className="opacity-60">Click para seleccionar</span>}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ function SectionPanel({ title, icon: Icon, color, children, id }: { title: strin
|
|||||||
===================================================== */
|
===================================================== */
|
||||||
export function AcademicSections({ planId, color }: { planId: string; color?: string | null }) {
|
export function AcademicSections({ planId, color }: { planId: string; color?: string | null }) {
|
||||||
const qc = useQueryClient()
|
const qc = useQueryClient()
|
||||||
|
if(!planId) return <div>Cargando…</div>
|
||||||
const { data: plan } = useSuspenseQuery(planTextOptions(planId))
|
const { data: plan } = useSuspenseQuery(planTextOptions(planId))
|
||||||
|
|
||||||
const [editing, setEditing] = useState<null | { key: keyof PlanTextFields; title: string }>(null)
|
const [editing, setEditing] = useState<null | { key: keyof PlanTextFields; title: string }>(null)
|
||||||
@@ -175,17 +176,18 @@ export function AcademicSections({ planId, color }: { planId: string; color?: st
|
|||||||
>
|
>
|
||||||
Copiar
|
Copiar
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
{s.key !== "prompt" &&
|
||||||
variant="ghost"
|
(<Button
|
||||||
size="sm"
|
variant="ghost"
|
||||||
onClick={() => {
|
size="sm"
|
||||||
const current = Array.isArray(text) ? text.join("\n") : (text ?? "")
|
onClick={() => {
|
||||||
setEditing({ key: s.key, title: s.title })
|
const current = Array.isArray(text) ? text.join("\n") : (text ?? "")
|
||||||
setDraft(current)
|
setEditing({ key: s.key, title: s.title })
|
||||||
}}
|
setDraft(current)
|
||||||
>
|
}}
|
||||||
Editar
|
>
|
||||||
</Button>
|
Editar
|
||||||
|
</Button>)}
|
||||||
</div>
|
</div>
|
||||||
</SectionPanel>
|
</SectionPanel>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ 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"
|
||||||
|
|
||||||
type LoaderData = { planId: string }
|
type LoaderData = { plan: PlanFull; asignaturas: AsignaturaLite[] }
|
||||||
|
|
||||||
export const Route = createFileRoute("/_authenticated/plan/$planId")({
|
export const Route = createFileRoute("/_authenticated/plan/$planId")({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
@@ -34,24 +34,24 @@ export const Route = createFileRoute("/_authenticated/plan/$planId")({
|
|||||||
|
|
||||||
loader: async ({ params, context: { queryClient } }): Promise<LoaderData> => {
|
loader: async ({ params, context: { queryClient } }): Promise<LoaderData> => {
|
||||||
const { planId } = params
|
const { planId } = params
|
||||||
await Promise.all([
|
if (!planId) throw new Error("planId is required")
|
||||||
|
console.log("Cargando planId", planId)
|
||||||
|
const [plan, asignaturas] = await Promise.all([
|
||||||
queryClient.ensureQueryData(planByIdOptions(planId)),
|
queryClient.ensureQueryData(planByIdOptions(planId)),
|
||||||
queryClient.ensureQueryData(asignaturasCountOptions(planId)),
|
// queryClient.ensureQueryData(asignaturasCountOptions(planId)),
|
||||||
queryClient.ensureQueryData(asignaturasPreviewOptions(planId)),
|
queryClient.ensureQueryData(asignaturasPreviewOptions(planId)),
|
||||||
])
|
])
|
||||||
return { planId }
|
|
||||||
|
return { plan, asignaturas }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// ...existing code...
|
// ...existing code...
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
const qc = useQueryClient()
|
const qc = useQueryClient()
|
||||||
const { planId } = Route.useLoaderData() as LoaderData
|
const { plan, asignaturas: asignaturasPreview } = Route.useLoaderData() as LoaderData
|
||||||
const auth = useSupabaseAuth()
|
const auth = useSupabaseAuth()
|
||||||
|
const asignaturasCount = asignaturasPreview.length
|
||||||
const { data: plan } = useSuspenseQuery(planByIdOptions(planId))
|
|
||||||
const { data: asignaturasCount } = useSuspenseQuery(asignaturasCountOptions(planId))
|
|
||||||
const { data: asignaturasPreview } = useSuspenseQuery(asignaturasPreviewOptions(planId))
|
|
||||||
|
|
||||||
const showFacultad = auth.claims?.role === 'lci' || auth.claims?.role === 'vicerrectoria'
|
const showFacultad = auth.claims?.role === 'lci' || auth.claims?.role === 'vicerrectoria'
|
||||||
const showCarrera = auth.claims?.role === 'secretario_academico'
|
const showCarrera = auth.claims?.role === 'secretario_academico'
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ function RouteComponent() {
|
|||||||
className="bg-white/60"
|
className="bg-white/60"
|
||||||
style={{ borderColor: (chipTint(fac?.color).borderColor as string) }}
|
style={{ borderColor: (chipTint(fac?.color).borderColor as string) }}
|
||||||
>
|
>
|
||||||
{p.estado}
|
{p.estado && p.estado.length > 10 ? `${p.estado.slice(0, 10)}…` : p.estado}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ function RouteComponent() {
|
|||||||
<div className="grid gap-4 md:grid-cols-2">
|
<div className="grid gap-4 md:grid-cols-2">
|
||||||
<div className="space-y-1"><Label>Nombre</Label><Input value={form.nombre ?? ""} onChange={(e) => setForm((s) => ({ ...s, nombre: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Nombre</Label><Input value={form.nombre ?? ""} onChange={(e) => setForm((s) => ({ ...s, nombre: e.target.value }))} /></div>
|
||||||
<div className="space-y-1"><Label>Apellidos</Label><Input value={form.apellidos ?? ""} onChange={(e) => setForm((s) => ({ ...s, apellidos: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Apellidos</Label><Input value={form.apellidos ?? ""} onChange={(e) => setForm((s) => ({ ...s, apellidos: e.target.value }))} /></div>
|
||||||
<div className="space-y-1"><Label>Título</Label><Input value={form.title ?? ""} onChange={(e) => setForm((s) => ({ ...s, title: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Título <small>(opcional)</small></Label><Input value={form.title ?? ""} onChange={(e) => setForm((s) => ({ ...s, title: e.target.value }))} /></div>
|
||||||
<div className="space-y-1"><Label>Clave</Label><Input value={form.clave ?? ""} onChange={(e) => setForm((s) => ({ ...s, clave: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Clave</Label><Input value={form.clave ?? ""} onChange={(e) => setForm((s) => ({ ...s, clave: e.target.value }))} /></div>
|
||||||
<div className="space-y-1"><Label>Avatar (URL)</Label><Input value={form.avatar ?? ""} onChange={(e) => setForm((s) => ({ ...s, avatar: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Avatar (URL)</Label><Input value={form.avatar ?? ""} onChange={(e) => setForm((s) => ({ ...s, avatar: e.target.value }))} /></div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
@@ -472,7 +472,7 @@ function RouteComponent() {
|
|||||||
|
|
||||||
<div className="space-y-1"><Label>Nombre</Label><Input value={createForm.nombre ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, nombre: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Nombre</Label><Input value={createForm.nombre ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, nombre: e.target.value }))} /></div>
|
||||||
<div className="space-y-1"><Label>Apellidos</Label><Input value={createForm.apellidos ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, apellidos: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Apellidos</Label><Input value={createForm.apellidos ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, apellidos: e.target.value }))} /></div>
|
||||||
<div className="space-y-1"><Label>Título</Label><Input value={createForm.title ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, title: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Título <small>(opcional)</small></Label><Input value={createForm.title ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, title: e.target.value }))} /></div>
|
||||||
<div className="space-y-1"><Label>Clave</Label><Input value={createForm.clave ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, clave: e.target.value }))} /></div>
|
<div className="space-y-1"><Label>Clave</Label><Input value={createForm.clave ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, clave: e.target.value }))} /></div>
|
||||||
<div className="space-y-1 md:col-span-2"><Label>Avatar (URL)</Label><Input value={createForm.avatar ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, avatar: e.target.value }))} /></div>
|
<div className="space-y-1 md:col-span-2"><Label>Avatar (URL)</Label><Input value={createForm.avatar ?? ""} onChange={(e) => setCreateForm((s) => ({ ...s, avatar: e.target.value }))} /></div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user