From a51fa6b1fc28e7ea4a9796ce7ab8bd08efc165c4 Mon Sep 17 00:00:00 2001 From: "Roberto.silva" Date: Tue, 24 Feb 2026 12:33:27 -0600 Subject: [PATCH] =?UTF-8?q?A=C3=B1adir=20Bibliograf=C3=ADa=20fix=20#128?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asignaturas/detalle/BibliographyItem.tsx | 122 +++++++++++------- src/data/api/subjects.api.ts | 48 +++++++ src/data/hooks/useSubjects.ts | 41 ++++++ 3 files changed, 166 insertions(+), 45 deletions(-) diff --git a/src/components/asignaturas/detalle/BibliographyItem.tsx b/src/components/asignaturas/detalle/BibliographyItem.tsx index acec679..2067498 100644 --- a/src/components/asignaturas/detalle/BibliographyItem.tsx +++ b/src/components/asignaturas/detalle/BibliographyItem.tsx @@ -1,6 +1,9 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/label-has-associated-control */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ import { useParams } from '@tanstack/react-router' import { Plus, Search, BookOpen, Trash2, Library, Edit3 } from 'lucide-react' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { AlertDialog, @@ -31,7 +34,12 @@ import { SelectValue, } from '@/components/ui/select' import { Textarea } from '@/components/ui/textarea' -import { useSubjectBibliografia } from '@/data/hooks/useSubjects' +import { + useCreateBibliografia, + useDeleteBibliografia, + useSubjectBibliografia, + useUpdateBibliografia, +} from '@/data/hooks/useSubjects' import { cn } from '@/lib/utils' // --- Interfaces --- @@ -50,9 +58,16 @@ export function BibliographyItem() { from: '/planes/$planId/asignaturas/$asignaturaId', }) - const { data: bibliografia2, isLoading: loadinasignatura } = + // --- 1. Única fuente de verdad: La Query --- + const { data: bibliografia = [], isLoading } = useSubjectBibliografia(asignaturaId) - const [entries, setEntries] = useState>([]) + + // --- 2. Mutaciones --- + const { mutate: crearBibliografia } = useCreateBibliografia() + const { mutate: actualizarBibliografia } = useUpdateBibliografia(asignaturaId) + const { mutate: eliminarBibliografia } = useDeleteBibliografia(asignaturaId) + + // --- 3. Estados de UI (Solo para diálogos y edición) --- const [isAddDialogOpen, setIsAddDialogOpen] = useState(false) const [isLibraryDialogOpen, setIsLibraryDialogOpen] = useState(false) const [deleteId, setDeleteId] = useState(null) @@ -61,29 +76,27 @@ export function BibliographyItem() { 'BASICA', ) - useEffect(() => { - console.log(entries) - - if (bibliografia2 && Array.isArray(bibliografia2)) { - setEntries(bibliografia2) - } - }, [bibliografia2]) - - const basicaEntries = entries.filter((e) => e.tipo === 'BASICA') - const complementariaEntries = entries.filter( + console.log('Datos actuales en el front:', bibliografia) + // --- 4. Derivación de datos (Se calculan en cada render) --- + const basicaEntries = bibliografia.filter((e) => e.tipo === 'BASICA') + const complementariaEntries = bibliografia.filter( (e) => e.tipo === 'COMPLEMENTARIA', ) - console.log(bibliografia2) + + // --- Handlers Conectados a la Base de Datos --- const handleAddManual = (cita: string) => { - const newEntry: BibliografiaEntry = { - id: `manual-${Date.now()}`, - tipo: newEntryType, - cita, - } - setEntries([...entries, newEntry]) - setIsAddDialogOpen(false) - // toast.success('Referencia manual añadida'); + crearBibliografia( + { + asignatura_id: asignaturaId, + tipo: newEntryType, + cita, + tipo_fuente: 'MANUAL', + }, + { + onSuccess: () => setIsAddDialogOpen(false), + }, + ) } const handleAddFromLibrary = ( @@ -91,22 +104,43 @@ export function BibliographyItem() { tipo: 'BASICA' | 'COMPLEMENTARIA', ) => { const cita = `${resource.autor} (${resource.anio}). ${resource.titulo}. ${resource.editorial}.` - const newEntry: BibliografiaEntry = { - id: `lib-ref-${Date.now()}`, - tipo, - cita, - fuenteBibliotecaId: resource.id, - fuenteBiblioteca: resource, - } - setEntries([...entries, newEntry]) - setIsLibraryDialogOpen(false) - // toast.success('Añadido desde biblioteca'); + crearBibliografia( + { + asignatura_id: asignaturaId, + tipo, + cita, + tipo_fuente: 'BIBLIOTECA', + biblioteca_item_id: resource.id, + }, + { + onSuccess: () => setIsLibraryDialogOpen(false), + }, + ) } - const handleUpdateCita = (id: string, cita: string) => { - setEntries(entries.map((e) => (e.id === id ? { ...e, cita } : e))) + const handleUpdateCita = (id: string, nuevaCita: string) => { + actualizarBibliografia( + { + id, + updates: { cita: nuevaCita }, + }, + { + onSuccess: () => setEditingId(null), + }, + ) } + const onConfirmDelete = () => { + if (deleteId) { + eliminarBibliografia(deleteId, { + onSuccess: () => setDeleteId(null), + }) + } + } + + if (isLoading) + return
Cargando bibliografía...
+ return (
@@ -134,9 +168,13 @@ export function BibliographyItem() { e.fuenteBibliotecaId || '')} + // CORRECCIÓN: Usamos 'bibliografia' en lugar de 'entries' + existingIds={bibliografia.map( + (e) => e.biblioteca_item_id || '', + )} /> @@ -216,13 +254,7 @@ export function BibliographyItem() { Cancelar - { - setEntries(entries.filter((e) => e.id !== deleteId)) - setDeleteId(null) - }} - className="bg-red-600" - > + Eliminar @@ -412,7 +444,7 @@ function LibrarySearchDialog({ resources, onSelect, existingIds }: any) {
- {filtered.map((res) => ( + {filtered.map((res: any) => (
onSelect(res, tipo)} diff --git a/src/data/api/subjects.api.ts b/src/data/api/subjects.api.ts index 56a8e11..dd6bcb0 100644 --- a/src/data/api/subjects.api.ts +++ b/src/data/api/subjects.api.ts @@ -490,3 +490,51 @@ export async function lineas_delete(lineaId: string) { if (error) throw error return lineaId } + +export async function bibliografia_insert(entry: { + asignatura_id: string + tipo: 'BASICA' | 'COMPLEMENTARIA' + cita: string + tipo_fuente: 'MANUAL' | 'BIBLIOTECA' + biblioteca_item_id?: string | null +}) { + const supabase = supabaseBrowser() + const { data, error } = await supabase + .from('bibliografia_asignatura') + .insert([entry]) + .select() + .single() + + if (error) throw error + return data +} + +export async function bibliografia_update( + id: string, + updates: { + cita?: string + tipo?: 'BASICA' | 'COMPLEMENTARIA' + }, +) { + const supabase = supabaseBrowser() + const { data, error } = await supabase + .from('bibliografia_asignatura') + .update(updates) // Ahora 'updates' es compatible con lo que espera Supabase + .eq('id', id) + .select() + .single() + + if (error) throw error + return data +} + +export async function bibliografia_delete(id: string) { + const supabase = supabaseBrowser() + const { error } = await supabase + .from('bibliografia_asignatura') + .delete() + .eq('id', id) + + if (error) throw error + return id +} diff --git a/src/data/hooks/useSubjects.ts b/src/data/hooks/useSubjects.ts index 9975763..29dba1e 100644 --- a/src/data/hooks/useSubjects.ts +++ b/src/data/hooks/useSubjects.ts @@ -3,6 +3,9 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { ai_generate_subject, asignaturas_update, + bibliografia_delete, + bibliografia_insert, + bibliografia_update, lineas_insert, lineas_update, subjects_bibliografia_list, @@ -276,3 +279,41 @@ export function useUpdateLinea() { }, }) } + +export function useCreateBibliografia() { + const queryClient = useQueryClient() + return useMutation({ + mutationFn: bibliografia_insert, + onSuccess: (data) => { + // USAR LA MISMA LLAVE QUE EL HOOK DE LECTURA + queryClient.invalidateQueries({ + queryKey: qk.asignaturaBibliografia(data.asignatura_id), + }) + }, + }) +} + +export function useUpdateBibliografia(asignaturaId: string) { + const qc = useQueryClient() + return useMutation({ + mutationFn: ({ id, updates }: { id: string; updates: any }) => + bibliografia_update(id, updates), + onSuccess: () => { + qc.invalidateQueries({ + queryKey: qk.asignaturaBibliografia(asignaturaId), + }) + }, + }) +} + +export function useDeleteBibliografia(asignaturaId: string) { + const queryClient = useQueryClient() + return useMutation({ + mutationFn: (id: string) => bibliografia_delete(id), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: qk.asignaturaBibliografia(asignaturaId), + }) + }, + }) +}