import { useRouterState } from '@tanstack/react-router' import { Sparkles, Send, Target, UserCheck, Lightbulb, FileText, GraduationCap, BookOpen, Check, X, } from 'lucide-react' import { useState, useEffect, useRef, useMemo } from 'react' import type { IAMessage, IASugerencia, CampoEstructura, } from '@/types/asignatura' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { ScrollArea } from '@/components/ui/scroll-area' import { Textarea } from '@/components/ui/textarea' import { cn } from '@/lib/utils' // Tipos importados de tu archivo de asignatura const PRESETS = [ { id: 'mejorar-objetivo', label: 'Mejorar objetivo', icon: Target, prompt: 'Mejora la redacción del objetivo de esta asignatura...', }, { id: 'contenido-tematico', label: 'Sugerir contenido', icon: BookOpen, prompt: 'Genera un desglose de temas para esta asignatura...', }, { id: 'actividades', label: 'Actividades de aprendizaje', icon: GraduationCap, prompt: 'Sugiere actividades prácticas para los temas seleccionados...', }, { id: 'bibliografia', label: 'Actualizar bibliografía', icon: FileText, prompt: 'Recomienda bibliografía reciente para esta asignatura...', }, ] interface SelectedField { key: string label: string value: string } interface IAAsignaturaTabProps { campos: Array datosGenerales: Record messages: Array onSendMessage: (message: string, campoId?: string) => void onAcceptSuggestion: (sugerencia: IASugerencia) => void onRejectSuggestion: (messageId: string) => void } export function IAAsignaturaTab({ campos, datosGenerales, messages, onSendMessage, onAcceptSuggestion, onRejectSuggestion, }: IAAsignaturaTabProps) { const routerState = useRouterState() // ESTADOS PRINCIPALES (Igual que en Planes) const [input, setInput] = useState('') const [selectedFields, setSelectedFields] = useState>([]) const [showSuggestions, setShowSuggestions] = useState(false) const [isLoading, setIsLoading] = useState(false) const scrollRef = useRef(null) // 1. Transformar datos de la asignatura para el menú const availableFields = useMemo(() => { // Extraemos las claves directamente del objeto datosGenerales // ["nombre", "descripcion", "perfil_de_egreso", "fines_de_aprendizaje_o_formacion"] if (!datosGenerales.datos) return [] return Object.keys(datosGenerales.datos).map((key) => { // Buscamos si existe un nombre amigable en la estructura de campos const estructuraCampo = campos.find((c) => c.id === key) // Si existe en 'campos', usamos su nombre; si no, formateamos la clave (ej: perfil_de_egreso -> Perfil De Egreso) const labelAmigable = estructuraCampo?.nombre || key.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase()) return { key: key, label: labelAmigable, value: String(datosGenerales[key] || ''), } }) }, [campos, datosGenerales]) // 2. Manejar el estado inicial si viene de "Datos de Asignatura" (Prefill) useEffect(() => { const state = routerState.location.state as any if (state?.prefillCampo && availableFields.length > 0) { console.log(state?.prefillCampo) console.log(availableFields) const field = availableFields.find((f) => f.key === state.prefillCampo) if (field && !selectedFields.find((sf) => sf.key === field.key)) { setSelectedFields([field]) // Sincronizamos el texto inicial con el campo pre-seleccionado setInput(`Mejora el campo ${field.label}: `) } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [availableFields]) // Scroll automático useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight } }, [messages, isLoading]) // 3. Lógica para el disparador ":" const handleInputChange = (e: React.ChangeEvent) => { const val = e.target.value setInput(val) setShowSuggestions(val.endsWith(':')) } const toggleField = (field: SelectedField) => { setSelectedFields((prev) => { const isSelected = prev.find((f) => f.key === field.key) // 1. Si ya está seleccionado, lo quitamos (Toggle OFF) if (isSelected) { return prev.filter((f) => f.key !== field.key) } // 2. Si no está, lo agregamos a la lista (Toggle ON) const newSelected = [...prev, field] // 3. Actualizamos el texto del input para reflejar los títulos (labels) setInput((prevText) => { // Separamos lo que el usuario escribió antes del disparador ":" // y lo que viene después (posibles keys/labels previos) const parts = prevText.split(':') const beforeColon = parts[0] // Creamos un string con los labels de todos los campos seleccionados const labelsPath = newSelected.map((f) => f.label).join(', ') return `${beforeColon.trim()}: ${labelsPath} ` }) return newSelected }) // Opcional: mantener abierto si quieres que el usuario elija varios seguidos // setShowSuggestions(false) } const buildPrompt = (userInput: string) => { if (selectedFields.length === 0) return userInput const fieldsText = selectedFields .map((f) => `- ${f.label}: ${f.value || '(vacio)'}`) .join('\n') return `${userInput}\n\nCampos a analizar:\n${fieldsText}`.trim() } const handleSend = async (promptOverride?: string) => { const rawText = promptOverride || input if (!rawText.trim() && selectedFields.length === 0) return const finalPrompt = buildPrompt(rawText) setIsLoading(true) // Llamamos a la función que viene por props onSendMessage(finalPrompt, selectedFields[0]?.key) setInput('') setSelectedFields([]) // Simular carga local para el feedback visual setTimeout(() => setIsLoading(false), 1200) } return (
{/* PANEL DE CHAT PRINCIPAL */}
{/* Barra superior */}
IA de Asignatura
{/* CONTENIDO DEL CHAT */}
{messages.map((msg) => (
{msg.role === 'assistant' ? ( ) : ( )}
{msg.content}
{/* Renderizado de Sugerencias (Homologado con lógica de Asignatura) */} {msg.sugerencia && !msg.sugerencia.aceptada && (

Propuesta para: {msg.sugerencia.campoNombre}

{msg.sugerencia.valorSugerido}
)} {msg.sugerencia?.aceptada && ( Sugerencia aplicada )}
))} {isLoading && (
)}
{/* INPUT FIJO AL FONDO */}
{/* MENÚ DE SUGERENCIAS FLOTANTE */} {showSuggestions && (
Seleccionar campo de asignatura
{availableFields.map((field) => ( ))}
)} {/* CONTENEDOR DEL INPUT */}
{/* Visualización de Tags */} {selectedFields.length > 0 && (
{selectedFields.map((field) => (
Campo: {field.label}
))}
)}