import React, { useState, useRef, useEffect } from 'react'; import { Upload, Brain, CheckCircle, AlertCircle, Download, FileText, Activity, TrendingUp } from 'lucide-react'; import { Button, Card, Badge } from '../../../ui'; import { OnboardingStepProps } from '../OnboardingWizard'; import { useModal } from '../../../../hooks/ui/useModal'; import { useToast } from '../../../../hooks/ui/useToast'; import { useOnboarding } from '../../../../hooks/business/onboarding'; import { useAuthUser, useAuthLoading } from '../../../../stores/auth.store'; import { useCurrentTenant, useTenantLoading } from '../../../../stores'; type ProcessingStage = 'upload' | 'validating' | 'analyzing' | 'completed' | 'error'; interface ProcessingResult { // Validation data is_valid: boolean; total_records: number; unique_products: number; product_list: string[]; validation_errors: string[]; validation_warnings: string[]; summary: { date_range: string; total_sales: number; average_daily_sales: number; }; // Analysis data productsIdentified: number; categoriesDetected: number; businessModel: string; confidenceScore: number; recommendations: string[]; } // This function has been replaced by the onboarding hooks export const DataProcessingStep: React.FC = ({ data, onDataChange, onNext, onPrevious, isFirstStep, isLastStep }) => { const user = useAuthUser(); const authLoading = useAuthLoading(); const currentTenant = useCurrentTenant(); const tenantLoading = useTenantLoading(); // Use the new onboarding hooks const { processSalesFile, generateInventorySuggestions, salesProcessing: { stage: onboardingStage, progress: onboardingProgress, currentMessage: onboardingMessage, validationResults, suggestions }, isLoading, error, clearError } = useOnboarding(); const errorModal = useModal(); const toast = useToast(); // Check if we're still loading user or tenant data const isLoadingUserData = authLoading || tenantLoading; // Get tenant ID from multiple sources with fallback const getTenantId = (): string | null => { const tenantId = currentTenant?.id || user?.tenant_id || null; console.log('DataProcessingStep - getTenantId:', { currentTenant: currentTenant?.id, userTenantId: user?.tenant_id, finalTenantId: tenantId, isLoadingUserData, authLoading, tenantLoading, user: user ? { id: user.id, email: user.email } : null }); return tenantId; }; // Check if tenant data is available (not loading and has ID) const isTenantAvailable = (): boolean => { return !isLoadingUserData && getTenantId() !== null; }; // Use onboarding hook state when available, fallback to local state const [localStage, setLocalStage] = useState(data.processingStage || 'upload'); const [uploadedFile, setUploadedFile] = useState(data.files?.salesData || null); const [localResults, setLocalResults] = useState(data.processingResults || null); // Derive current state from onboarding hooks or local state const stage = onboardingStage || localStage; const progress = onboardingProgress || 0; const currentMessage = onboardingMessage || ''; const results = (validationResults && suggestions) ? { ...validationResults, aiSuggestions: suggestions, // Add calculated fields productsIdentified: validationResults.product_list?.length || 0, categoriesDetected: suggestions ? new Set(suggestions.map((s: any) => s.category)).size : 0, businessModel: 'production', confidenceScore: 85, recommendations: [] } : localResults; const [dragActive, setDragActive] = useState(false); const fileInputRef = useRef(null); useEffect(() => { // Update parent data when state changes onDataChange({ ...data, processingStage: stage, processingProgress: progress, currentMessage: currentMessage, processingResults: results, suggestions: suggestions, files: { ...data.files, salesData: uploadedFile } }); }, [stage, progress, currentMessage, results, suggestions, uploadedFile, onDataChange, data]); const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); setDragActive(true); }; const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); setDragActive(false); }; const handleDrop = (e: React.DragEvent) => { e.preventDefault(); setDragActive(false); const files = Array.from(e.dataTransfer.files); if (files.length > 0) { handleFileUpload(files[0]); } }; const handleFileSelect = (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { handleFileUpload(e.target.files[0]); } }; const handleFileUpload = async (file: File) => { // Validate file type const validExtensions = ['.csv', '.xlsx', '.xls', '.json']; const fileExtension = file.name.toLowerCase().substring(file.name.lastIndexOf('.')); if (!validExtensions.includes(fileExtension)) { toast.addToast('Formato de archivo no válido. Usa CSV, JSON o Excel (.xlsx, .xls)', { title: 'Formato inválido', type: 'error' }); return; } // Check file size (max 10MB) if (file.size > 10 * 1024 * 1024) { toast.addToast('El archivo es demasiado grande. Máximo 10MB permitido.', { title: 'Archivo muy grande', type: 'error' }); return; } setUploadedFile(file); setLocalStage('validating'); try { // Wait for user data to load if still loading if (!isTenantAvailable()) { console.log('Tenant not available, waiting...'); setUploadedFile(null); setLocalStage('upload'); toast.addToast('Por favor espere mientras cargamos su información...', { title: 'Esperando datos de usuario', type: 'info' }); return; } console.log('DataProcessingStep - Starting file processing'); // Use the onboarding hook for file processing const success = await processSalesFile(file, (progress, stage, message) => { console.log(`Processing: ${progress}% - ${stage} - ${message}`); }); if (success) { setLocalStage('completed'); toast.addToast('El archivo se procesó correctamente', { title: 'Procesamiento completado', type: 'success' }); } else { throw new Error('Error procesando el archivo'); } } catch (error) { console.error('DataProcessingStep - Processing error:', error); setLocalStage('error'); const errorMessage = error instanceof Error ? error.message : 'Error en el procesamiento de datos'; toast.addToast(errorMessage, { title: 'Error en el procesamiento', type: 'error' }); } }; const downloadTemplate = () => { // Provide a static CSV template const csvContent = `fecha,producto,cantidad,precio_unitario,precio_total,cliente,canal_venta 2024-01-15,Pan Integral,5,2.50,12.50,Cliente A,Tienda 2024-01-15,Croissant,3,1.80,5.40,Cliente B,Online 2024-01-15,Baguette,2,3.00,6.00,Cliente C,Tienda 2024-01-16,Pan de Centeno,4,2.80,11.20,Cliente A,Tienda 2024-01-16,Empanadas,6,4.50,27.00,Cliente D,Delivery`; const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', 'plantilla_ventas.csv'); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); toast.addToast('La plantilla se descargó correctamente.', { title: 'Plantilla descargada', type: 'success' }); }; const resetProcess = () => { setLocalStage('upload'); setUploadedFile(null); setLocalResults(null); if (fileInputRef.current) { fileInputRef.current.value = ''; } if (error) { clearError(); } }; return (
{/* Loading state when tenant data is not available */} {!isTenantAvailable() && (

Cargando datos de usuario...

Por favor espere mientras cargamos su información de tenant

)} {/* Improved Upload Stage */} {(stage === 'idle' || localStage === 'upload') && isTenantAvailable() && ( <>
fileInputRef.current?.click()} >
{uploadedFile ? ( <>

¡Perfecto! Archivo listo

📄 {uploadedFile.name}

{(uploadedFile.size / 1024 / 1024).toFixed(2)} MB • Listo para procesar

) : ( <>

Sube tu historial de ventas

Arrastra y suelta tu archivo aquí, o haz clic para seleccionar

{/* Visual indicators */}
📊
CSV
📈
Excel
Hasta 10MB
)}
💡 Formatos aceptados: CSV, Excel (XLSX, XLS) • Tamaño máximo: 10MB
{/* Improved Template Download Section */}

¿Necesitas ayuda con el formato?

Descarga nuestra plantilla Excel con ejemplos y formato correcto para tus datos de ventas

)} {/* Processing Stages */} {(stage === 'validating' || stage === 'analyzing') && (
{stage === 'validating' ? ( ) : ( )}

{stage === 'validating' ? 'Validando datos...' : 'Analizando con IA...'}

{currentMessage}

{/* Progress Bar */}
Progreso {progress}%
{/* Processing Steps */}
= 40 ? 'bg-[var(--color-success)]/10 text-[var(--color-success)]' : 'bg-[var(--bg-secondary)]' }`}> Validación
= 70 ? 'bg-[var(--color-success)]/10 text-[var(--color-success)]' : 'bg-[var(--bg-secondary)]' }`}> Análisis IA
= 100 ? 'bg-[var(--color-success)]/10 text-[var(--color-success)]' : 'bg-[var(--bg-secondary)]' }`}> Completo
)} {/* Simplified Results Stage */} {stage === 'completed' && results && (
{/* Success Header */}

¡Procesamiento Completado!

Tus datos han sido procesados exitosamente

{/* Simple Stats Cards */}

{results.total_records}

Registros

{results.productsIdentified}

Productos

{results.confidenceScore}%

Confianza

{results.businessModel === 'artisan' ? 'Artesanal' : results.businessModel === 'retail' ? 'Retail' : 'Híbrido'}

Modelo

)} {/* Error State */} {stage === 'error' && (

Error en el procesamiento

{currentMessage}

)}
); };