fix #114: refactorización de AsignaturaDetailPage y hooks relacionados: persistencia, caché y tipado
- Persistencia de cambios de "Datos generales" usando updateAsignatura.mutate. - Corregido el manejo de caché: uso de qk centralizada y merge en setQueryData para no perder relaciones. - Corregidos los tipos devueltos por subjects_get. - Evitado estado inválido tras guardar (merge local + actualización de cache). Verificar: editar → guardar → volver al plan → reingresar muestra datos actualizados sin parpadeos.
This commit is contained in:
@@ -7,7 +7,11 @@ import type { DocumentoResult } from './plans.api'
|
||||
import type {
|
||||
Asignatura,
|
||||
BibliografiaAsignatura,
|
||||
CarreraRow,
|
||||
CambioAsignatura,
|
||||
EstructuraAsignatura,
|
||||
FacultadRow,
|
||||
PlanEstudioRow,
|
||||
TipoAsignatura,
|
||||
UUID,
|
||||
} from '../types/domain'
|
||||
@@ -34,7 +38,55 @@ const EDGE = {
|
||||
subjects_get_document: 'subjects_get_document',
|
||||
} as const
|
||||
|
||||
export async function subjects_get(subjectId: UUID): Promise<Asignatura> {
|
||||
export type FacultadInSubject = Pick<
|
||||
FacultadRow,
|
||||
'id' | 'nombre' | 'nombre_corto' | 'color' | 'icono'
|
||||
>
|
||||
|
||||
export type CarreraInSubject = Pick<
|
||||
CarreraRow,
|
||||
'id' | 'facultad_id' | 'nombre' | 'nombre_corto' | 'clave_sep' | 'activa'
|
||||
> & {
|
||||
facultades: FacultadInSubject | null
|
||||
}
|
||||
|
||||
export type PlanEstudioInSubject = Pick<
|
||||
PlanEstudioRow,
|
||||
| 'id'
|
||||
| 'carrera_id'
|
||||
| 'estructura_id'
|
||||
| 'nombre'
|
||||
| 'nivel'
|
||||
| 'tipo_ciclo'
|
||||
| 'numero_ciclos'
|
||||
| 'datos'
|
||||
| 'estado_actual_id'
|
||||
| 'activo'
|
||||
| 'tipo_origen'
|
||||
| 'meta_origen'
|
||||
| 'creado_por'
|
||||
| 'actualizado_por'
|
||||
| 'creado_en'
|
||||
| 'actualizado_en'
|
||||
> & {
|
||||
carreras: CarreraInSubject | null
|
||||
}
|
||||
|
||||
export type EstructuraAsignaturaInSubject = Pick<
|
||||
EstructuraAsignatura,
|
||||
'id' | 'nombre' | 'version' | 'definicion'
|
||||
>
|
||||
|
||||
/**
|
||||
* Tipo real que devuelve `subjects_get` (asignatura + relaciones seleccionadas).
|
||||
* Nota: `asignaturas_update` (update directo) NO devuelve estas relaciones.
|
||||
*/
|
||||
export type AsignaturaDetail = Asignatura & {
|
||||
planes_estudio: PlanEstudioInSubject | null
|
||||
estructuras_asignatura: EstructuraAsignaturaInSubject | null
|
||||
}
|
||||
|
||||
export async function subjects_get(subjectId: UUID): Promise<AsignaturaDetail> {
|
||||
const supabase = supabaseBrowser()
|
||||
|
||||
const { data, error } = await supabase
|
||||
|
||||
@@ -97,7 +97,6 @@ export function useCreateSubjectManual() {
|
||||
}
|
||||
|
||||
export function useGenerateSubjectAI() {
|
||||
const qc = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: ai_generate_subject,
|
||||
})
|
||||
@@ -162,7 +161,9 @@ export function useUpdateSubjectFields() {
|
||||
mutationFn: (vars: { subjectId: UUID; patch: SubjectsUpdateFieldsPatch }) =>
|
||||
subjects_update_fields(vars.subjectId, vars.patch),
|
||||
onSuccess: (updated) => {
|
||||
qc.setQueryData(qk.asignatura(updated.id), updated)
|
||||
qc.setQueryData(qk.asignatura(updated.id), (prev) =>
|
||||
prev ? { ...(prev as any), ...(updated as any) } : updated,
|
||||
)
|
||||
qc.invalidateQueries({
|
||||
queryKey: qk.planAsignaturas(updated.plan_estudio_id),
|
||||
})
|
||||
@@ -178,7 +179,9 @@ export function useUpdateSubjectContenido() {
|
||||
mutationFn: (vars: { subjectId: UUID; unidades: Array<any> }) =>
|
||||
subjects_update_contenido(vars.subjectId, vars.unidades),
|
||||
onSuccess: (updated) => {
|
||||
qc.setQueryData(qk.asignatura(updated.id), updated)
|
||||
qc.setQueryData(qk.asignatura(updated.id), (prev) =>
|
||||
prev ? { ...(prev as any), ...(updated as any) } : updated,
|
||||
)
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(updated.id) })
|
||||
},
|
||||
})
|
||||
@@ -221,17 +224,22 @@ export function useUpdateAsignatura() {
|
||||
}) => asignaturas_update(vars.asignaturaId, vars.patch),
|
||||
|
||||
onSuccess: (updated) => {
|
||||
// 1. Actualizamos la materia específica en la caché si tienes un query de "detalle"
|
||||
qc.setQueryData(['asignatura', updated.id], updated)
|
||||
// ✅ Mantener consistencia con las query keys centralizadas (qk)
|
||||
// 1) Actualiza el detalle (esto evita volver a entrar con caché vieja)
|
||||
qc.setQueryData(qk.asignatura(updated.id), (prev) =>
|
||||
prev ? { ...(prev as any), ...(updated as any) } : updated,
|
||||
)
|
||||
|
||||
// 2. IMPORTANTÍSIMO: Invalidamos la lista de materias del plan
|
||||
// para que el mapa curricular vea los cambios (créditos, horas, nombre, etc.)
|
||||
// 2) Refresca vistas derivadas del plan
|
||||
qc.invalidateQueries({
|
||||
queryKey: ['plan_asignaturas', updated.plan_estudio_id],
|
||||
queryKey: qk.planAsignaturas(updated.plan_estudio_id),
|
||||
})
|
||||
qc.invalidateQueries({
|
||||
queryKey: qk.planHistorial(updated.plan_estudio_id),
|
||||
})
|
||||
|
||||
// 3. Si tienes una lista general de asignaturas, también la invalidamos
|
||||
qc.invalidateQueries({ queryKey: ['asignaturas', 'list'] })
|
||||
// 3) Refresca historial de la asignatura si existe
|
||||
qc.invalidateQueries({ queryKey: qk.asignaturaHistorial(updated.id) })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user