Se agrega avance de historial de chat y referencias de la ia
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||||
import { createFileRoute, useRouterState } from '@tanstack/react-router'
|
import { createFileRoute, useRouterState } from '@tanstack/react-router'
|
||||||
import {
|
import {
|
||||||
Sparkles,
|
Sparkles,
|
||||||
@@ -10,6 +11,8 @@ import {
|
|||||||
BookOpen,
|
BookOpen,
|
||||||
Check,
|
Check,
|
||||||
X,
|
X,
|
||||||
|
MessageSquarePlus,
|
||||||
|
Trash2,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useState, useEffect, useRef, useMemo } from 'react'
|
import { useState, useEffect, useRef, useMemo } from 'react'
|
||||||
|
|
||||||
@@ -84,6 +87,52 @@ function RouteComponent() {
|
|||||||
const [pendingSuggestion, setPendingSuggestion] = useState<any>(null)
|
const [pendingSuggestion, setPendingSuggestion] = useState<any>(null)
|
||||||
|
|
||||||
const scrollRef = useRef<HTMLDivElement>(null)
|
const scrollRef = useRef<HTMLDivElement>(null)
|
||||||
|
const [activeChatId, setActiveChatId] = useState('1')
|
||||||
|
const [chatHistory, setChatHistory] = useState([
|
||||||
|
{ id: '1', title: 'Chat inicial' },
|
||||||
|
])
|
||||||
|
const [allMessages, setAllMessages] = useState<{ [key: string]: Array<any> }>(
|
||||||
|
{
|
||||||
|
'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
|
// 1. Transformar datos de la API para el menú de selección
|
||||||
const availableFields = useMemo(() => {
|
const availableFields = useMemo(() => {
|
||||||
@@ -208,6 +257,49 @@ ${fieldsText}
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="flex h-[calc(100vh-160px)] max-h-[calc(100vh-160px)] w-full gap-6 overflow-hidden p-4">
|
<div className="flex h-[calc(100vh-160px)] max-h-[calc(100vh-160px)] w-full gap-6 overflow-hidden p-4">
|
||||||
|
{/* --- PANEL IZQUIERDO: HISTORIAL (NUEVO) --- */}
|
||||||
|
<div className="flex w-64 flex-col border-r pr-4">
|
||||||
|
<div className="mb-4">
|
||||||
|
<h2 className="mb-4 px-2 text-xs font-bold tracking-wider text-slate-500 uppercase">
|
||||||
|
Chats
|
||||||
|
</h2>
|
||||||
|
<Button
|
||||||
|
onClick={createNewChat}
|
||||||
|
variant="outline"
|
||||||
|
className="mb-4 w-full justify-start gap-2 border-slate-200 hover:bg-teal-50 hover:text-teal-700"
|
||||||
|
>
|
||||||
|
<MessageSquarePlus size={18} /> Nuevo chat
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ScrollArea className="flex-1">
|
||||||
|
<div className="space-y-1">
|
||||||
|
{chatHistory.map((chat) => (
|
||||||
|
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
|
||||||
|
<div
|
||||||
|
key={chat.id}
|
||||||
|
onClick={() => 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'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<FileText size={16} className="shrink-0 opacity-40" />
|
||||||
|
<span className="truncate pr-6">{chat.title}</span>
|
||||||
|
|
||||||
|
{/* Botón de borrar que aparece al hacer hover */}
|
||||||
|
<button
|
||||||
|
onClick={(e) => deleteChat(e, chat.id)}
|
||||||
|
className="absolute right-2 p-1 opacity-0 transition-opacity group-hover:opacity-100 hover:text-red-600"
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
{/* PANEL DE CHAT PRINCIPAL */}
|
{/* PANEL DE CHAT PRINCIPAL */}
|
||||||
<div className="relative flex min-w-0 flex-[3] flex-col overflow-hidden rounded-xl border border-slate-200 bg-slate-50/50 shadow-sm">
|
<div className="relative flex min-w-0 flex-[3] flex-col overflow-hidden rounded-xl border border-slate-200 bg-slate-50/50 shadow-sm">
|
||||||
{/* NUEVO: Barra superior de campos seleccionados */}
|
{/* NUEVO: Barra superior de campos seleccionados */}
|
||||||
@@ -285,7 +377,6 @@ ${fieldsText}
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* INPUT FIJO AL FONDO CON SUGERENCIAS : */}
|
|
||||||
{/* INPUT FIJO AL FONDO CON SUGERENCIAS : */}
|
{/* INPUT FIJO AL FONDO CON SUGERENCIAS : */}
|
||||||
<div className="shrink-0 border-t bg-white p-4">
|
<div className="shrink-0 border-t bg-white p-4">
|
||||||
<div className="relative mx-auto max-w-4xl">
|
<div className="relative mx-auto max-w-4xl">
|
||||||
|
|||||||
Reference in New Issue
Block a user