// components/DataInputRedesigned.tsx // Interfaz de entrada de datos rediseñada y organizada import React, { useState } from 'react'; import { motion } from 'framer-motion'; import { Download, CheckCircle, AlertCircle, FileText, Database, UploadCloud, File, Sheet, Loader2, Sparkles, Table, Info, ExternalLink, X } from 'lucide-react'; import clsx from 'clsx'; import toast from 'react-hot-toast'; interface DataInputRedesignedProps { onAnalyze: (config: { costPerHour: number; avgCsat: number; segmentMapping?: { high_value_queues: string[]; medium_value_queues: string[]; low_value_queues: string[]; }; file?: File; sheetUrl?: string; useSynthetic?: boolean; }) => void; isAnalyzing: boolean; } const DataInputRedesigned: React.FC = ({ onAnalyze, isAnalyzing }) => { // Estados para datos manuales const [costPerHour, setCostPerHour] = useState(20); const [avgCsat, setAvgCsat] = useState(85); // Estados para mapeo de segmentación const [highValueQueues, setHighValueQueues] = useState(''); const [mediumValueQueues, setMediumValueQueues] = useState(''); const [lowValueQueues, setLowValueQueues] = useState(''); // Estados para carga de datos const [uploadMethod, setUploadMethod] = useState<'file' | 'url' | 'synthetic' | null>(null); const [file, setFile] = useState(null); const [sheetUrl, setSheetUrl] = useState(''); const [isGenerating, setIsGenerating] = useState(false); const [isDragging, setIsDragging] = useState(false); // Campos CSV requeridos const csvFields = [ { name: 'interaction_id', type: 'String único', example: 'call_8842910', required: true }, { name: 'datetime_start', type: 'DateTime', example: '2024-10-01 09:15:22', required: true }, { name: 'queue_skill', type: 'String', example: 'Soporte_Nivel1, Ventas', required: true }, { name: 'channel', type: 'String', example: 'Voice, Chat, WhatsApp', required: true }, { name: 'duration_talk', type: 'Segundos', example: '345', required: true }, { name: 'hold_time', type: 'Segundos', example: '45', required: true }, { name: 'wrap_up_time', type: 'Segundos', example: '30', required: true }, { name: 'agent_id', type: 'String', example: 'Agente_045', required: true }, { name: 'transfer_flag', type: 'Boolean', example: 'TRUE / FALSE', required: true }, { name: 'caller_id', type: 'String (hash)', example: 'Hash_99283', required: false }, { name: 'csat_score', type: 'Float', example: '4', required: false } ]; const handleDownloadTemplate = () => { const headers = csvFields.map(f => f.name).join(','); const exampleRow = csvFields.map(f => f.example).join(','); const csvContent = `${headers}\n${exampleRow}\n`; const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'plantilla_beyond_diagnostic.csv'; link.click(); toast.success('Plantilla CSV descargada', { icon: '📥' }); }; const handleFileChange = (selectedFile: File | null) => { if (selectedFile) { const allowedTypes = [ 'text/csv', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ]; if (allowedTypes.includes(selectedFile.type) || selectedFile.name.endsWith('.csv') || selectedFile.name.endsWith('.xlsx') || selectedFile.name.endsWith('.xls')) { setFile(selectedFile); setUploadMethod('file'); toast.success(`Archivo "${selectedFile.name}" cargado`, { icon: '📄' }); } else { toast.error('Tipo de archivo no válido. Sube un CSV o Excel.', { icon: '❌' }); } } }; const onDragOver = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(true); }; const onDragLeave = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); }; const onDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); const droppedFile = e.dataTransfer.files[0]; if (droppedFile) { handleFileChange(droppedFile); } }; const handleGenerateSynthetic = () => { setIsGenerating(true); setTimeout(() => { setUploadMethod('synthetic'); setIsGenerating(false); toast.success('Datos sintéticos generados para demo', { icon: '✨' }); }, 1500); }; const handleSheetUrlSubmit = () => { if (sheetUrl.trim()) { setUploadMethod('url'); toast.success('URL de Google Sheets conectada', { icon: '🔗' }); } else { toast.error('Introduce una URL válida', { icon: '❌' }); } }; const canAnalyze = uploadMethod !== null && costPerHour > 0; return (
{/* Sección 1: Datos Manuales */}

1. Datos Manuales

Introduce los parámetros de configuración para tu análisis

{/* Coste por Hora */}
setCostPerHour(parseFloat(e.target.value) || 0)} min="0" step="0.5" className="w-full pl-10 pr-20 py-3 border-2 border-slate-300 rounded-lg focus:ring-2 focus:ring-[#6D84E3] focus:border-[#6D84E3] transition text-lg font-semibold" placeholder="20" /> €/hora

Tipo: Número (decimal) | Ejemplo: 20

Incluye salario, cargas sociales, infraestructura, etc.

{/* CSAT Promedio */}
setAvgCsat(parseFloat(e.target.value) || 0)} min="0" max="100" step="1" className="w-full pr-16 py-3 border-2 border-slate-300 rounded-lg focus:ring-2 focus:ring-[#6D84E3] focus:border-[#6D84E3] transition text-lg font-semibold" placeholder="85" /> / 100

Tipo: Número (0-100) | Ejemplo: 85

Puntuación promedio de satisfacción del cliente

{/* Segmentación por Cola/Skill */}

Segmentación de Clientes por Cola/Skill Opcional

Identifica qué colas/skills corresponden a cada segmento de cliente. Separa múltiples colas con comas.

{/* High Value */}
setHighValueQueues(e.target.value)} placeholder="VIP, Premium, Enterprise" className="w-full px-4 py-3 border-2 border-slate-300 rounded-lg focus:ring-2 focus:ring-[#6D84E3] focus:border-[#6D84E3] transition" />

Colas para clientes de alto valor

{/* Medium Value */}
setMediumValueQueues(e.target.value)} placeholder="Soporte_General, Ventas" className="w-full px-4 py-3 border-2 border-slate-300 rounded-lg focus:ring-2 focus:ring-[#6D84E3] focus:border-[#6D84E3] transition" />

Colas para clientes estándar

{/* Low Value */}
setLowValueQueues(e.target.value)} placeholder="Basico, Trial, Freemium" className="w-full px-4 py-3 border-2 border-slate-300 rounded-lg focus:ring-2 focus:ring-[#6D84E3] focus:border-[#6D84E3] transition" />

Colas para clientes de bajo valor

Nota: Las colas no mapeadas se clasificarán automáticamente como "Medium". El matching es flexible (no distingue mayúsculas y permite coincidencias parciales).

{/* Sección 2: Datos CSV */}

2. Datos CSV (Raw Data de ACD)

Exporta estos campos desde tu sistema ACD/CTI (Genesys, Avaya, Talkdesk, Zendesk, etc.)

{/* Tabla de campos requeridos */}
{csvFields.map((field, index) => ( ))}
Campo Tipo Ejemplo Obligatorio
{field.name} {field.type} {field.example} {field.required ? ( ) : ( No )}

{/* Botón de descarga de plantilla */}

Descarga una plantilla con la estructura exacta de campos requeridos

{/* Opciones de carga */}

Elige cómo proporcionar tus datos:

{/* Opción 1: Subir archivo */}
setUploadMethod('file')} className="mt-1" />

Subir Archivo CSV/Excel

{uploadMethod === 'file' && (
{file ? (

{file.name}

{(file.size / 1024).toFixed(1)} KB

) : ( <>

Arrastra tu archivo aquí o haz click para seleccionar

handleFileChange(e.target.files?.[0] || null)} className="hidden" id="file-upload" /> )}
)}
{/* Opción 2: URL Google Sheets */}
setUploadMethod('url')} className="mt-1" />

Conectar Google Sheets

{uploadMethod === 'url' && (
setSheetUrl(e.target.value)} placeholder="https://docs.google.com/spreadsheets/d/..." className="flex-1 px-4 py-2 border-2 border-slate-300 rounded-lg focus:ring-2 focus:ring-[#6D84E3] focus:border-[#6D84E3] transition" />
)}
{/* Opción 3: Datos sintéticos */}
setUploadMethod('synthetic')} className="mt-1" />

Generar Datos Sintéticos (Demo)

{uploadMethod === 'synthetic' && ( )}
{/* Botón de análisis */}
); }; export default DataInputRedesigned;