import { createFileRoute } from '@tanstack/react-router' import { format, formatDistanceToNow, parseISO } from 'date-fns' import { es } from 'date-fns/locale' import { GitBranch, Edit3, PlusCircle, RefreshCw, User, Loader2, Clock, Eye, History, Calendar, } from 'lucide-react' import { useMemo, useState } from 'react' import { Badge } from '@/components/ui/badge' import { Card, CardContent } from '@/components/ui/card' import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { usePlanHistorial } from '@/data/hooks/usePlans' export const Route = createFileRoute('/planes/$planId/_detalle/historial')({ component: RouteComponent, }) const getEventConfig = (tipo: string, campo: string) => { if (tipo === 'CREACION') return { label: 'Creación', icon: , color: 'teal', } if (campo === 'estado') return { label: 'Cambio de estado', icon: , color: 'blue', } if (campo === 'datos') return { label: 'Edición de Datos', icon: , color: 'amber', } return { label: 'Actualización', icon: , color: 'slate', } } function RouteComponent() { const { planId } = Route.useParams() const { data: rawData, isLoading } = usePlanHistorial(planId) // ESTADOS PARA EL MODAL const [selectedEvent, setSelectedEvent] = useState(null) const [isModalOpen, setIsModalOpen] = useState(false) const historyEvents = useMemo(() => { if (!rawData) return [] return rawData.map((item: any) => { const config = getEventConfig(item.tipo, item.campo) return { id: item.id, type: config.label, user: item.cambiado_por === '11111111-1111-1111-1111-111111111111' ? 'Administrador' : 'Usuario Staff', description: item.campo === 'datos' ? `Actualización general de: ${item.valor_nuevo?.nombre || 'información del plan'}` : `Se modificó el campo ${item.campo}`, date: parseISO(item.cambiado_en), icon: config.icon, campo: item.campo, details: { from: item.valor_anterior, to: item.valor_nuevo, }, } }) }, [rawData]) const openCompareModal = (event: any) => { setSelectedEvent(event) setIsModalOpen(true) } const renderValue = (val: any) => { if (!val) return 'Sin información' if (typeof val === 'object') return JSON.stringify(val, null, 2) return String(val) } if (isLoading) return ( ) return ( Historial de Cambios del Plan Registro cronológico de modificaciones realizadas {historyEvents.length === 0 ? ( No hay registros. ) : ( historyEvents.map((event) => ( {event.icon} {/* LÍNEA SUPERIOR: Título a la izquierda --- Usuario, Botón y Fecha a la derecha */} {event.type} {formatDistanceToNow(event.date, { addSuffix: true, locale: es, })} {/* Grupo de elementos alineados a la derecha */} {/* Usuario e Icono */} {event.user} {/* Botón Ver Cambios */} openCompareModal(event)} className="group/btn flex items-center gap-1.5 text-xs transition-colors hover:text-teal-600" > Ver cambios {/* Fecha exacta (Solo visible en desktop para no amontonar) */} {format(event.date, 'yyyy-MM-dd HH:mm')} {/* LÍNEA INFERIOR: Descripción */} {event.description} {/* Badges de transición opcionales (de estado) */} {event.details && typeof event.details.from === 'string' && event.campo === 'estado' && ( {event.details.from} → {event.details.to} )} )) )} {/* MODAL DE COMPARACIÓN CON SCROLL INTERNO */} Comparación de Versiones {selectedEvent?.user} {' '} {selectedEvent && format(selectedEvent.date, "d 'de' MMMM, HH:mm", { locale: es, })} {/* Lado Antes */} Versión Anterior {renderValue(selectedEvent?.details.from)} {/* Lado Después */} Nueva Versión {renderValue(selectedEvent?.details.to)} Campo: {selectedEvent?.campo} ) }
Registro cronológico de modificaciones realizadas
{event.description}