Se crea funcionalidad de exportar pdf desde front y generar historial de version de cambios se agrego una libreri jspdf
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "react"
|
||||
import { supabase } from "@/auth/supabase"
|
||||
import { supabase,useSupabaseAuth } from "@/auth/supabase"
|
||||
import { Button } from "../ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
@@ -35,11 +35,13 @@ export function EditBibliografiaButton({
|
||||
const [open, setOpen] = useState(false)
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [text, setText] = useState("")
|
||||
const auth = useSupabaseAuth()
|
||||
|
||||
const initialTextRef = useRef("")
|
||||
const lines = useMemo(() => parseLines(text), [text])
|
||||
const dirty = useMemo(() => initialTextRef.current !== text, [text])
|
||||
|
||||
// 🔹 Abre el editor y carga los valores actuales
|
||||
function openEditor() {
|
||||
const start = (value ?? []).join("\n")
|
||||
setText(start)
|
||||
@@ -47,52 +49,110 @@ export function EditBibliografiaButton({
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
// ✅ Función para generar diferencias tipo JSON Patch
|
||||
function generateDiff(oldRefs: string[], newRefs: string[]) {
|
||||
const changes: any[] = []
|
||||
|
||||
// Si son distintos en contenido o longitud
|
||||
if (JSON.stringify(oldRefs) !== JSON.stringify(newRefs)) {
|
||||
changes.push({
|
||||
op: "replace",
|
||||
path: "/bibliografia",
|
||||
from: oldRefs,
|
||||
value: newRefs,
|
||||
})
|
||||
}
|
||||
|
||||
return changes
|
||||
}
|
||||
|
||||
async function save() {
|
||||
setSaving(true)
|
||||
try {
|
||||
setSaving(true)
|
||||
const refs = parseLines(text)
|
||||
// 1️⃣ Obtener bibliografía anterior
|
||||
const { data: oldData, error: oldError } = await supabase
|
||||
.from("asignaturas")
|
||||
.select("bibliografia")
|
||||
.eq("id", asignaturaId)
|
||||
.maybeSingle()
|
||||
|
||||
if (oldError) throw oldError
|
||||
|
||||
const oldRefs = oldData?.bibliografia ?? []
|
||||
const newRefs = parseLines(text)
|
||||
|
||||
// 2️⃣ Generar diferencias
|
||||
const diff = generateDiff(oldRefs, newRefs)
|
||||
|
||||
// 3️⃣ Guardar respaldo si hay cambios
|
||||
if (diff.length > 0) {
|
||||
const { error: backupError } = await supabase
|
||||
.from("historico_cambios_asignaturas") // misma tabla de respaldo
|
||||
.insert({
|
||||
id_asignatura: asignaturaId,
|
||||
json_cambios: diff, // jsonb
|
||||
user_id: auth.user?.id,
|
||||
created_at: new Date().toISOString(),
|
||||
})
|
||||
|
||||
if (backupError) throw backupError
|
||||
}
|
||||
|
||||
// 4️⃣ Actualizar bibliografía en asignaturas
|
||||
const { data, error } = await supabase
|
||||
.from("asignaturas")
|
||||
.update({ bibliografia: refs })
|
||||
.update({ bibliografia: newRefs })
|
||||
.eq("id", asignaturaId)
|
||||
.select()
|
||||
.maybeSingle()
|
||||
|
||||
if (error) throw error
|
||||
|
||||
onSaved((data as any)?.bibliografia ?? refs)
|
||||
initialTextRef.current = refs.join("\n")
|
||||
toast.success(`${refs.length} referencia(s) guardada(s).`)
|
||||
// 5️⃣ Refrescar estado local
|
||||
onSaved((data as any)?.bibliografia ?? newRefs)
|
||||
initialTextRef.current = newRefs.join("\n")
|
||||
toast.success(`${newRefs.length} referencia(s) guardada(s).`)
|
||||
setOpen(false)
|
||||
} catch (e: any) {
|
||||
toast.error(e?.message ?? "No se pudo guardar")
|
||||
} catch (err: any) {
|
||||
toast.error(err.message ?? "No se pudo guardar la bibliografía")
|
||||
} finally {
|
||||
setSaving(false)
|
||||
}
|
||||
}
|
||||
|
||||
// Acciones
|
||||
// 🔧 Acciones extra
|
||||
function actionTrim() {
|
||||
const next = parseLines(text).map((s) => s.replace(/\s+/g, " ").trim())
|
||||
setText(next.join("\n"))
|
||||
}
|
||||
|
||||
function actionDedupe() {
|
||||
const seen = new Set<string>()
|
||||
const next: string[] = []
|
||||
for (const l of parseLines(text)) {
|
||||
const k = l.toLowerCase()
|
||||
if (!seen.has(k)) { seen.add(k); next.push(l) }
|
||||
if (!seen.has(k)) {
|
||||
seen.add(k)
|
||||
next.push(l)
|
||||
}
|
||||
}
|
||||
setText(next.join("\n"))
|
||||
}
|
||||
|
||||
function actionSort() {
|
||||
const next = [...parseLines(text)].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }))
|
||||
const next = [...parseLines(text)].sort((a, b) =>
|
||||
a.localeCompare(b, undefined, { sensitivity: "base" }),
|
||||
)
|
||||
setText(next.join("\n"))
|
||||
}
|
||||
|
||||
async function actionImportClipboard() {
|
||||
try {
|
||||
const clip = await navigator.clipboard.readText()
|
||||
if (!clip) { toast("Portapapeles vacío"); return }
|
||||
if (!clip) {
|
||||
toast("Portapapeles vacío")
|
||||
return
|
||||
}
|
||||
const next = [...parseLines(text), ...parseLines(clip)]
|
||||
setText(next.join("\n"))
|
||||
toast.success("Texto importado")
|
||||
@@ -100,6 +160,7 @@ export function EditBibliografiaButton({
|
||||
toast.error(e?.message ?? "No se pudo leer el portapapeles")
|
||||
}
|
||||
}
|
||||
|
||||
async function actionExportClipboard() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(parseLines(text).join("\n"))
|
||||
@@ -109,7 +170,7 @@ export function EditBibliografiaButton({
|
||||
}
|
||||
}
|
||||
|
||||
// Atajo guardar
|
||||
// ⌨️ Atajo Ctrl+S
|
||||
useEffect(() => {
|
||||
function onKey(e: KeyboardEvent) {
|
||||
if (!open) return
|
||||
@@ -120,7 +181,6 @@ export function EditBibliografiaButton({
|
||||
}
|
||||
window.addEventListener("keydown", onKey)
|
||||
return () => window.removeEventListener("keydown", onKey)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [open, saving, dirty, text])
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user