From ba188329dcbfca298fb7a161d3bd8615e0310646 Mon Sep 17 00:00:00 2001 From: "Roberto.silva" Date: Tue, 10 Feb 2026 14:33:04 -0600 Subject: [PATCH 1/2] Se agrega avance de historial de chat y referencias de la ia --- src/routes/planes/$planId/_detalle/iaplan.tsx | 93 ++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/src/routes/planes/$planId/_detalle/iaplan.tsx b/src/routes/planes/$planId/_detalle/iaplan.tsx index e6724af..44faa3a 100644 --- a/src/routes/planes/$planId/_detalle/iaplan.tsx +++ b/src/routes/planes/$planId/_detalle/iaplan.tsx @@ -1,3 +1,4 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ import { createFileRoute, useRouterState } from '@tanstack/react-router' import { Sparkles, @@ -10,6 +11,8 @@ import { BookOpen, Check, X, + MessageSquarePlus, + Trash2, } from 'lucide-react' import { useState, useEffect, useRef, useMemo } from 'react' @@ -84,6 +87,52 @@ function RouteComponent() { const [pendingSuggestion, setPendingSuggestion] = useState(null) const scrollRef = useRef(null) + const [activeChatId, setActiveChatId] = useState('1') + const [chatHistory, setChatHistory] = useState([ + { id: '1', title: 'Chat inicial' }, + ]) + const [allMessages, setAllMessages] = useState<{ [key: string]: Array }>( + { + '1': [ + { + id: 'm1', + role: 'assistant', + content: '¡Hola! Soy tu asistente de IA en este chat inicial.', + }, + ], + }, + ) + const currentMessages = allMessages[activeChatId] || [] + + const createNewChat = () => { + const newId = Date.now().toString() + const newChat = { id: newId, title: `Nuevo chat ${chatHistory.length + 1}` } + + setChatHistory([newChat, ...chatHistory]) + setAllMessages({ + ...allMessages, + [newId]: [ + { + id: '1', + role: 'assistant', + content: '¡Nuevo chat creado! ¿En qué puedo ayudarte?', + }, + ], + }) + setActiveChatId(newId) + } + + const deleteChat = (e: React.MouseEvent, id: string) => { + e.stopPropagation() // Evita que se seleccione el chat al borrarlo + + const newHistory = chatHistory.filter((chat) => chat.id !== id) + setChatHistory(newHistory) + + // Si borramos el chat activo, pasamos al primero disponible + if (activeChatId === id && newHistory.length > 0) { + setActiveChatId(newHistory[0].id) + } + } // 1. Transformar datos de la API para el menú de selección const availableFields = useMemo(() => { @@ -208,6 +257,49 @@ ${fieldsText} } return (
+ {/* --- PANEL IZQUIERDO: HISTORIAL (NUEVO) --- */} +
+
+

+ Chats +

+ +
+ + +
+ {chatHistory.map((chat) => ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events +
setActiveChatId(chat.id)} + className={`group relative flex w-full cursor-pointer items-center gap-3 rounded-lg px-3 py-3 text-sm transition-colors ${ + activeChatId === chat.id + ? 'bg-slate-100 font-medium text-slate-900' + : 'text-slate-600 hover:bg-slate-50' + }`} + > + + {chat.title} + + {/* Botón de borrar que aparece al hacer hover */} + +
+ ))} +
+
+
{/* PANEL DE CHAT PRINCIPAL */}
{/* NUEVO: Barra superior de campos seleccionados */} @@ -285,7 +377,6 @@ ${fieldsText} )}
- {/* INPUT FIJO AL FONDO CON SUGERENCIAS : */} {/* INPUT FIJO AL FONDO CON SUGERENCIAS : */}
-- 2.49.1 From d9a6852f43ace9fe8f65d1e041e6da7baa5b5c78 Mon Sep 17 00:00:00 2001 From: "Roberto.silva" Date: Wed, 11 Feb 2026 10:22:14 -0600 Subject: [PATCH 2/2] Se agrega drawer de referencias de ia y panel de historial de chats --- package.json | 3 +- src/components/ui/drawer.tsx | 133 ++++++++++++++++++ src/routes/planes/$planId/_detalle/iaplan.tsx | 67 ++++++++- 3 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 src/components/ui/drawer.tsx diff --git a/package.json b/package.json index 09f62f0..7a9ab10 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,8 @@ "tailwind-merge": "^3.4.0", "tailwindcss": "^4.0.6", "tw-animate-css": "^1.3.6", - "use-debounce": "^10.1.0" + "use-debounce": "^10.1.0", + "vaul": "^1.1.2" }, "devDependencies": { "@tanstack/devtools-vite": "^0.3.11", diff --git a/src/components/ui/drawer.tsx b/src/components/ui/drawer.tsx new file mode 100644 index 0000000..869955f --- /dev/null +++ b/src/components/ui/drawer.tsx @@ -0,0 +1,133 @@ +import * as React from "react" +import { Drawer as DrawerPrimitive } from "vaul" + +import { cn } from "@/lib/utils" + +function Drawer({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerTrigger({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerPortal({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerClose({ + ...props +}: React.ComponentProps) { + return +} + +function DrawerOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DrawerContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + +
+ {children} + + + ) +} + +function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DrawerTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DrawerDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + Drawer, + DrawerPortal, + DrawerOverlay, + DrawerTrigger, + DrawerClose, + DrawerContent, + DrawerHeader, + DrawerFooter, + DrawerTitle, + DrawerDescription, +} diff --git a/src/routes/planes/$planId/_detalle/iaplan.tsx b/src/routes/planes/$planId/_detalle/iaplan.tsx index 44faa3a..f9a98e2 100644 --- a/src/routes/planes/$planId/_detalle/iaplan.tsx +++ b/src/routes/planes/$planId/_detalle/iaplan.tsx @@ -16,8 +16,12 @@ import { } from 'lucide-react' import { useState, useEffect, useRef, useMemo } from 'react' +import type { UploadedFile } from '@/components/planes/wizard/PasoDetallesPanel/FileDropZone' + +import ReferenciasParaIA from '@/components/planes/wizard/PasoDetallesPanel/ReferenciasParaIA' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Button } from '@/components/ui/button' +import { Drawer, DrawerContent } from '@/components/ui/drawer' import { ScrollArea } from '@/components/ui/scroll-area' import { Textarea } from '@/components/ui/textarea' import { usePlan } from '@/data/hooks/usePlans' @@ -56,20 +60,24 @@ interface SelectedField { value: string } -const formatLabel = (key: string) => { - const result = key.replace(/_/g, ' ') - return result.charAt(0).toUpperCase() + result.slice(1) -} - export const Route = createFileRoute('/planes/$planId/_detalle/iaplan')({ component: RouteComponent, }) function RouteComponent() { const { planId } = Route.useParams() - // Usamos el ID dinámico del plan o el hardcoded según tu necesidad + const { data } = usePlan('0e0aea4d-b8b4-4e75-8279-6224c3ac769f') const routerState = useRouterState() + const [openIA, setOpenIA] = useState(false) + // archivos + const [selectedArchivoIds, setSelectedArchivoIds] = useState>( + [], + ) + const [selectedRepositorioIds, setSelectedRepositorioIds] = useState< + Array + >([]) + const [uploadedFiles, setUploadedFiles] = useState>([]) // ESTADOS PRINCIPALES const [messages, setMessages] = useState>([ @@ -146,6 +154,10 @@ function RouteComponent() { ) }, [data]) + useEffect(() => { + console.log(uploadedFiles) + }, [uploadedFiles]) + // 2. Manejar el estado inicial si viene de "Datos Generales" useEffect(() => { const state = routerState.location.state as any @@ -304,10 +316,16 @@ ${fieldsText}
{/* NUEVO: Barra superior de campos seleccionados */}
-
+
Mejorar con IA +
@@ -477,6 +495,41 @@ ${fieldsText} ))}
+ + + +
+

Referencias para la IA

+ +
+ +
+ { + setSelectedArchivoIds((prev) => + checked ? [...prev, id] : prev.filter((a) => a !== id), + ) + }} + onToggleRepositorio={(id, checked) => { + setSelectedRepositorioIds((prev) => + checked ? [...prev, id] : prev.filter((r) => r !== id), + ) + }} + onFilesChange={(files) => { + setUploadedFiles(files) + }} + /> +
+
+
) } -- 2.49.1