diff --git a/src/components/historico/HistorialCambiosModal.tsx b/src/components/historico/HistorialCambiosModal.tsx new file mode 100644 index 0000000..225e432 --- /dev/null +++ b/src/components/historico/HistorialCambiosModal.tsx @@ -0,0 +1,92 @@ +import { useQuery } from "@tanstack/react-query" +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { supabase } from "@/auth/supabase" +import ReactMarkdown from "react-markdown" +import { useSupabaseAuth } from "@/auth/supabase" + +export function HistorialCambiosModal({ + open, + onClose, + planId, + onRestore, // 🔥 recibiremos una función del padre para restaurar +}: { + open: boolean + onClose: () => void + planId: string + onRestore: (key: string, value: string) => void +}) { + const auth = useSupabaseAuth() + + const { data, isLoading, error } = useQuery({ + queryKey: ["historico_cambios", planId, auth.user?.id], + queryFn: async () => { + const { data, error } = await supabase + .from("historico_cambios") + .select("id, json_cambios, user_id, created_at") + .eq("id_plan_estudios", planId) + .eq("user_id", auth.user?.id) // ✅ filtro por usuario actual + .order("created_at", { ascending: false }) + + if (error) throw error + return data + }, + enabled: !!auth.user?.id, // ✅ solo corre si hay usuario autenticado + }) + + return ( + + + + Histórico de cambios + + + {isLoading && Cargando historial...} + {error && Error al cargar: {String(error)}} + {!isLoading && !error && (!data || data.length === 0) && ( + No hay cambios registrados. + )} + + + {data?.map((item) => { + const diff = item.json_cambios?.[0] + const key = diff?.path?.replace("/", "") + return ( + + + Usuario: {item.user_id || "Desconocido"} + {new Date(item.created_at).toLocaleString()} + + + + Campo: {key} + Antes: {diff?.from || "—"} + Después: {diff?.value || "—"} + + + onRestore(key, diff.from)} + > + Restaurar + + + ) + })} + + + + + Cerrar + + + + + ) + +} diff --git a/src/components/planes/academic-sections.tsx b/src/components/planes/academic-sections.tsx index da3baa4..170031f 100644 --- a/src/components/planes/academic-sections.tsx +++ b/src/components/planes/academic-sections.tsx @@ -7,6 +7,7 @@ import { Textarea } from "@/components/ui/textarea" import { supabase,useSupabaseAuth } from "@/auth/supabase" import { toast } from "sonner" import ReactMarkdown from 'react-markdown' +import { HistorialCambiosModal } from "../historico/HistorialCambiosModal" /* ===================================================== @@ -27,6 +28,7 @@ export type PlanTextFields = { indicadores_desempeno?: string | string[] | null pertinencia?: string | string[] | null prompt?: string | null + historico?: string | null } async function fetchPlanText(planId: string): Promise { @@ -112,6 +114,7 @@ function SectionPanel({ title, icon: Icon, color, children, id }: { title: strin export function AcademicSections({ planId, color }: { planId: string; color?: string | null }) { const qc = useQueryClient() const auth = useSupabaseAuth() + const [openHistorial, setOpenHistorial] = useState(false) if(!planId) return Cargando… const { data: plan } = useSuspenseQuery(planTextOptions(planId)) @@ -155,6 +158,7 @@ export function AcademicSections({ planId, color }: { planId: string; color?: st { id: "sec-ind", title: "Indicadores de desempeño", icon: Icons.LineChart, key: "indicadores_desempeno" as const, mono: false }, { id: "sec-per", title: "Pertinencia", icon: Icons.Lightbulb, key: "pertinencia" as const, mono: false }, { id: "sec-prm", title: "Prompt (origen)", icon: Icons.Code2, key: "prompt" as const, mono: true }, + { id: "sec-hist", title: "Histórico de cambios", icon: Icons.History, key: "historico" as const, mono: false } ], [] ) @@ -163,38 +167,48 @@ export function AcademicSections({ planId, color }: { planId: string; color?: st <> {sections.map((s) => { - const text = plan[s.key] ?? null - return ( - - - - { - const toCopy = Array.isArray(text) ? text.join("\n") : (text ?? "") - if (toCopy) navigator.clipboard.writeText(toCopy) - }} - > - Copiar - - {s.key !== "prompt" && - ( + {s.key === "historico" ? ( + setOpenHistorial(true)}> + Ver historial + + ) : ( + <> + + + { - const current = Array.isArray(text) ? text.join("\n") : (text ?? "") - setEditing({ key: s.key, title: s.title }) - setDraft(current) + const toCopy = Array.isArray(text) ? text.join("\n") : (text ?? "") + if (toCopy) navigator.clipboard.writeText(toCopy) }} > - Editar - )} - - - ) - })} + Copiar + + {s.key !== "prompt" && ( + { + const current = Array.isArray(text) ? text.join("\n") : (text ?? "") + setEditing({ key: s.key, title: s.title }) + setDraft(current) + }} + > + Editar + + )} + + > + )} + + ) + })} + {/* Diálogo de edición */} @@ -257,7 +271,14 @@ export function AcademicSections({ planId, color }: { planId: string; color?: st - + setOpenHistorial(false)} + planId={planId} + onRestore={async (key, value) => { + updateField.mutate({ key, value }) + }} + /> > ) }
Cargando historial...
Error al cargar: {String(error)}
No hay cambios registrados.
Campo: {key}
Antes: {diff?.from || "—"}
Después: {diff?.value || "—"}