import { useParams } from '@tanstack/react-router' import { format, parseISO } from 'date-fns' import { es } from 'date-fns/locale' import { History, FileText, List, BookMarked, Sparkles, FileCheck, Filter, Calendar, Loader2, Eye, } from 'lucide-react' import { useState, useMemo } from 'react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent } from '@/components/ui/card' import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { DropdownMenu, DropdownMenuContent, DropdownMenuCheckboxItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { useSubjectHistorial } from '@/data/hooks/useSubjects' import { cn } from '@/lib/utils' const tipoConfig: Record = { datos: { label: 'Datos generales', icon: FileText, color: 'text-info' }, contenido: { label: 'Contenido temático', icon: List, color: 'text-accent', }, bibliografia: { label: 'Bibliografía', icon: BookMarked, color: 'text-success', }, ia: { label: 'IA', icon: Sparkles, color: 'text-amber-500' }, documento: { label: 'Documento SEP', icon: FileCheck, color: 'text-primary', }, } export function HistorialTab() { const { asignaturaId } = useParams({ from: '/planes/$planId/asignaturas/$asignaturaId/historial', }) // 1. Obtenemos los datos directamente dentro del componente const { data: rawData, isLoading } = useSubjectHistorial(asignaturaId) const [filtros, setFiltros] = useState>( new Set(['datos', 'contenido', 'bibliografia', 'ia', 'documento']), ) // ESTADOS PARA EL MODAL const [selectedChange, setSelectedChange] = useState(null) const [isModalOpen, setIsModalOpen] = useState(false) const RenderValue = ({ value }: { value: any }) => { // 1. Caso: Nulo o vacío if ( value === null || value === undefined || value === 'Sin información previa' ) { return ( Sin información ) } // 2. Caso: Es un ARRAY (como tu lista de unidades) if (Array.isArray(value)) { return (
{value.map((item, index) => (
))}
) } // 3. Caso: Es un OBJETO (como cada unidad con titulo, temas, etc.) if (typeof value === 'object') { return (
{Object.entries(value).map(([key, val]) => (
{key.replace(/_/g, ' ')}
{/* Llamada recursiva para manejar lo que haya dentro del valor */} {typeof val === 'object' ? (
) : ( String(val) )}
))}
) } // 4. Caso: Texto o número simple return {String(value)} } const historialTransformado = useMemo(() => { if (!rawData) return [] return rawData.map((item: any) => ({ id: item.id, tipo: item.campo === 'contenido_tematico' ? 'contenido' : 'datos', descripcion: `Se actualizó el campo ${item.campo.replace('_', ' ')}`, fecha: parseISO(item.cambiado_en), usuario: item.fuente === 'HUMANO' ? 'Usuario Staff' : 'Sistema IA', detalles: { campo: item.campo, valor_anterior: item.valor_anterior || 'Sin datos previos', // Asumiendo que existe en tu API valor_nuevo: item.valor_nuevo, }, })) }, [rawData]) const openCompareModal = (cambio: any) => { setSelectedChange(cambio) setIsModalOpen(true) } const toggleFiltro = (tipo: string) => { const newFiltros = new Set(filtros) if (newFiltros.has(tipo)) newFiltros.delete(tipo) else newFiltros.add(tipo) setFiltros(newFiltros) } // 3. Aplicamos filtros y agrupamiento sobre los datos transformados const filteredHistorial = historialTransformado.filter((cambio) => filtros.has(cambio.tipo), ) const groupedHistorial = filteredHistorial.reduce( (groups, cambio) => { const dateKey = format(cambio.fecha, 'yyyy-MM-dd') if (!groups[dateKey]) groups[dateKey] = [] groups[dateKey].push(cambio) return groups }, {} as Record>, ) const sortedDates = Object.keys(groupedHistorial).sort((a, b) => b.localeCompare(a), ) if (isLoading) { return (
) } return (

Historial de cambios

{historialTransformado.length} cambios registrados

{/* Dropdown de Filtros (Igual al anterior) */} {Object.entries(tipoConfig).map(([tipo, config]) => ( toggleFiltro(tipo)} > {config.label} ))}
{filteredHistorial.length === 0 ? (

No se encontraron cambios.

) : (
{sortedDates.map((dateKey) => (

{format(parseISO(dateKey), "EEEE, d 'de' MMMM", { locale: es, })}

{groupedHistorial[dateKey].map((cambio) => { const config = tipoConfig[cambio.tipo] || tipoConfig.datos const Icon = config.icon return (

{cambio.descripcion}

{/* BOTÓN PARA VER CAMBIOS */} {format(cambio.fecha, 'HH:mm')}
{config.label} por {cambio.usuario}
) })}
))}
)} {/* MODAL DE COMPARACIÓN */} Comparación de cambios {/* ... info de usuario y fecha */}
{/* Lado Antes */}
Versión Anterior
{/* Lado Después */}
Nueva Versión
Campo modificado:{' '} {selectedChange?.detalles.campo}
) }