Files
acad-ia-2/src/data/hooks/useSubjects.ts
Guillermo Arrieta Medina 268ac064b1 Feat: generación IA de asignaturas, navegación con confetti y ajustes de API
closes #63:
- Añadido AIGenerateSubjectInput y nueva implementación ai_generate_subject que envía FormData (soporta archivosAdjuntos) al Edge Function.
- Creado hook useGenerateSubjectAI (mutation) y usado en WizardControls de asignaturas para generar la asignatura vía IA.
- WizardControls (asignaturas) construye el payload IA, invoca la mutación y navega al detalle de la asignatura creada pasando state.showConfetti para lanzar confetti.
- Ajustes en subjects.api.ts (nombres de endpoint, tipos y envío de datos) y sincronización de tipos en WizardControls (plan y campos básicos).
- Ruta de detalle de asignatura ($asignaturaId) ahora lee location.state.showConfetti y dispara lateralConfetti al entrar.
- Eliminado el prop onCreate del modal de nueva asignatura (la creación IA se gestiona internamente).
2026-02-05 13:22:16 -06:00

210 lines
5.8 KiB
TypeScript

import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import {
ai_generate_subject,
subjects_bibliografia_list,
subjects_clone_from_existing,
subjects_create_manual,
subjects_generate_document,
subjects_get,
subjects_get_document,
subjects_get_structure_catalog,
subjects_history,
subjects_import_from_file,
subjects_persist_from_ai,
subjects_update_bibliografia,
subjects_update_contenido,
subjects_update_fields,
} from '../api/subjects.api'
import { qk } from '../query/keys'
import type {
BibliografiaUpsertInput,
SubjectsCreateManualInput,
SubjectsUpdateFieldsPatch,
} from '../api/subjects.api'
import type { UUID } from '../types/domain'
export function useSubject(subjectId: UUID | null | undefined) {
return useQuery({
queryKey: subjectId
? qk.asignatura(subjectId)
: ['asignaturas', 'detail', null],
queryFn: () => subjects_get(subjectId as UUID),
enabled: Boolean(subjectId),
})
}
export function useSubjectBibliografia(subjectId: UUID | null | undefined) {
return useQuery({
queryKey: subjectId
? qk.asignaturaBibliografia(subjectId)
: ['asignaturas', 'bibliografia', null],
queryFn: () => subjects_bibliografia_list(subjectId as UUID),
enabled: Boolean(subjectId),
})
}
export function useSubjectHistorial(subjectId: UUID | null | undefined) {
return useQuery({
queryKey: subjectId
? qk.asignaturaHistorial(subjectId)
: ['asignaturas', 'historial', null],
queryFn: () => subjects_history(subjectId as UUID),
enabled: Boolean(subjectId),
})
}
export function useSubjectDocumento(subjectId: UUID | null | undefined) {
return useQuery({
queryKey: subjectId
? qk.asignaturaDocumento(subjectId)
: ['asignaturas', 'documento', null],
queryFn: () => subjects_get_document(subjectId as UUID),
enabled: Boolean(subjectId),
staleTime: 30_000,
})
}
export function useSubjectEstructuras() {
return useQuery({
queryKey: qk.estructurasAsignatura(),
queryFn: () => subjects_get_structure_catalog(),
})
}
/* ------------------ Mutations ------------------ */
export function useCreateSubjectManual() {
const qc = useQueryClient()
return useMutation({
mutationFn: (payload: SubjectsCreateManualInput) =>
subjects_create_manual(payload),
onSuccess: (subject) => {
qc.setQueryData(qk.asignatura(subject.id), subject)
qc.invalidateQueries({
queryKey: qk.planAsignaturas(subject.plan_estudio_id),
})
qc.invalidateQueries({
queryKey: qk.planHistorial(subject.plan_estudio_id),
})
},
})
}
export function useGenerateSubjectAI() {
const qc = useQueryClient()
return useMutation({
mutationFn: ai_generate_subject,
})
}
export function usePersistSubjectFromAI() {
const qc = useQueryClient()
return useMutation({
mutationFn: (payload: { planId: UUID; jsonAsignatura: any }) =>
subjects_persist_from_ai(payload),
onSuccess: (subject) => {
qc.setQueryData(qk.asignatura(subject.id), subject)
qc.invalidateQueries({
queryKey: qk.planAsignaturas(subject.plan_estudio_id),
})
qc.invalidateQueries({
queryKey: qk.planHistorial(subject.plan_estudio_id),
})
},
})
}
export function useCloneSubject() {
const qc = useQueryClient()
return useMutation({
mutationFn: subjects_clone_from_existing,
onSuccess: (subject) => {
qc.setQueryData(qk.asignatura(subject.id), subject)
qc.invalidateQueries({
queryKey: qk.planAsignaturas(subject.plan_estudio_id),
})
qc.invalidateQueries({
queryKey: qk.planHistorial(subject.plan_estudio_id),
})
},
})
}
export function useImportSubjectFromFile() {
const qc = useQueryClient()
return useMutation({
mutationFn: subjects_import_from_file,
onSuccess: (subject) => {
qc.setQueryData(qk.asignatura(subject.id), subject)
qc.invalidateQueries({
queryKey: qk.planAsignaturas(subject.plan_estudio_id),
})
qc.invalidateQueries({
queryKey: qk.planHistorial(subject.plan_estudio_id),
})
},
})
}
export function useUpdateSubjectFields() {
const qc = useQueryClient()
return useMutation({
mutationFn: (vars: { subjectId: UUID; patch: SubjectsUpdateFieldsPatch }) =>
subjects_update_fields(vars.subjectId, vars.patch),
onSuccess: (updated) => {
qc.setQueryData(qk.asignatura(updated.id), updated)
qc.invalidateQueries({
queryKey: qk.planAsignaturas(updated.plan_estudio_id),
})
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(updated.id) })
},
})
}
export function useUpdateSubjectContenido() {
const qc = useQueryClient()
return useMutation({
mutationFn: (vars: { subjectId: UUID; unidades: Array<any> }) =>
subjects_update_contenido(vars.subjectId, vars.unidades),
onSuccess: (updated) => {
qc.setQueryData(qk.asignatura(updated.id), updated)
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(updated.id) })
},
})
}
export function useUpdateSubjectBibliografia() {
const qc = useQueryClient()
return useMutation({
mutationFn: (vars: { subjectId: UUID; entries: BibliografiaUpsertInput }) =>
subjects_update_bibliografia(vars.subjectId, vars.entries),
onSuccess: (_ok, vars) => {
qc.invalidateQueries({
queryKey: qk.asignaturaBibliografia(vars.subjectId),
})
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(vars.subjectId) })
},
})
}
export function useGenerateSubjectDocumento() {
const qc = useQueryClient()
return useMutation({
mutationFn: (subjectId: UUID) => subjects_generate_document(subjectId),
onSuccess: (_doc, subjectId) => {
qc.invalidateQueries({ queryKey: qk.asignaturaDocumento(subjectId) })
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(subjectId) })
},
})
}