Fix new services implementation 5

This commit is contained in:
Urtzi Alfaro
2025-08-15 17:53:59 +02:00
parent 03b4d4185d
commit f7de9115d1
43 changed files with 1714 additions and 891 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import {
Sparkles, CheckCircle, Clock, ArrowRight, Coffee,
TrendingUp, Target, Loader, AlertTriangle, Mail,
@@ -18,6 +18,11 @@ interface SimplifiedTrainingProgressProps {
onTimeout?: () => void;
onBackgroundMode?: () => void;
onEmailNotification?: (email: string) => void;
// Optional WebSocket debugging info
websocketStatus?: string;
connectionError?: string;
isConnected?: boolean;
onRetryConnection?: () => void;
}
// Proceso simplificado de entrenamiento en 3 etapas
@@ -79,13 +84,18 @@ export default function SimplifiedTrainingProgress({
progress,
onTimeout,
onBackgroundMode,
onEmailNotification
onEmailNotification,
websocketStatus,
connectionError,
isConnected,
onRetryConnection
}: SimplifiedTrainingProgressProps) {
const [showDetails, setShowDetails] = useState(false);
const [showTimeoutOptions, setShowTimeoutOptions] = useState(false);
const [emailForNotification, setEmailForNotification] = useState('');
const [celebratingStage, setCelebratingStage] = useState<string | null>(null);
const [startTime] = useState(Date.now());
const celebratedStagesRef = useRef<Set<string>>(new Set());
// Show timeout options after 7 minutes for better UX
useEffect(() => {
@@ -98,17 +108,18 @@ export default function SimplifiedTrainingProgress({
return () => clearTimeout(timer);
}, [progress.status, progress.progress]);
// Celebrate stage completions
// Celebrate stage completions - fixed to prevent infinite re-renders
useEffect(() => {
TRAINING_STAGES.forEach(stage => {
if (progress.progress >= stage.progressRange[1] &&
celebratingStage !== stage.id &&
!celebratedStagesRef.current.has(stage.id) &&
progress.progress > 0) {
setCelebratingStage(stage.id);
celebratedStagesRef.current.add(stage.id);
setTimeout(() => setCelebratingStage(null), 3000);
}
});
}, [progress.progress, celebratingStage]);
}, [progress.progress]);
const getCurrentStage = () => {
return TRAINING_STAGES.find(stage =>
@@ -258,6 +269,36 @@ export default function SimplifiedTrainingProgress({
</p>
</div>
{/* Connection Status Debug Info */}
{(websocketStatus || connectionError) && (
<div className={`mb-4 p-3 rounded-lg text-sm ${
connectionError
? 'bg-red-50 text-red-800 border border-red-200'
: isConnected
? 'bg-green-50 text-green-800 border border-green-200'
: 'bg-yellow-50 text-yellow-800 border border-yellow-200'
}`}>
<div className="flex items-center justify-between">
<div>
<strong>Estado de conexión:</strong>
{connectionError
? ` Error - ${connectionError}`
: isConnected
? ' ✅ Conectado a tiempo real'
: ' ⏳ Conectando...'}
</div>
{connectionError && onRetryConnection && (
<button
onClick={onRetryConnection}
className="ml-2 px-3 py-1 bg-red-600 text-white text-xs rounded hover:bg-red-700 transition-colors"
>
Reintentar
</button>
)}
</div>
</div>
)}
{/* Optional Details */}
<button
onClick={() => setShowDetails(!showDetails)}

View File

@@ -10,7 +10,9 @@ import {
User,
Bell,
ChevronDown,
ChefHat
ChefHat,
Warehouse,
ShoppingCart
} from 'lucide-react';
interface LayoutProps {
@@ -42,6 +44,8 @@ const Layout: React.FC<LayoutProps> = ({
{ id: 'dashboard', label: 'Inicio', icon: Home, href: '/dashboard' },
{ id: 'orders', label: 'Pedidos', icon: Package, href: '/orders' },
{ id: 'production', label: 'Producción', icon: ChefHat, href: '/production' },
{ id: 'inventory', label: 'Inventario', icon: Warehouse, href: '/inventory' },
{ id: 'sales', label: 'Ventas', icon: ShoppingCart, href: '/sales' },
{ id: 'reports', label: 'Informes', icon: TrendingUp, href: '/reports' },
{ id: 'settings', label: 'Configuración', icon: Settings, href: '/settings' },
];

View File

@@ -245,7 +245,8 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
color: 'blue',
bgColor: 'bg-blue-50',
borderColor: 'border-blue-200',
textColor: 'text-blue-900'
textColor: 'text-blue-900',
businessType: 'bakery'
},
central_baker_satellite: {
icon: Truck,
@@ -254,7 +255,8 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
color: 'amber',
bgColor: 'bg-amber-50',
borderColor: 'border-amber-200',
textColor: 'text-amber-900'
textColor: 'text-amber-900',
businessType: 'bakery'
},
retail_bakery: {
icon: Store,
@@ -263,7 +265,8 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
color: 'green',
bgColor: 'bg-green-50',
borderColor: 'border-green-200',
textColor: 'text-green-900'
textColor: 'text-green-900',
businessType: 'bakery'
},
hybrid_bakery: {
icon: Settings2,
@@ -272,7 +275,28 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
color: 'purple',
bgColor: 'bg-purple-50',
borderColor: 'border-purple-200',
textColor: 'text-purple-900'
textColor: 'text-purple-900',
businessType: 'bakery'
},
coffee_shop_individual: {
icon: Coffee,
title: 'Cafetería Individual',
description: 'Servicio de bebidas y comida ligera con preparación in-situ',
color: 'amber',
bgColor: 'bg-amber-50',
borderColor: 'border-amber-200',
textColor: 'text-amber-900',
businessType: 'coffee_shop'
},
coffee_shop_chain: {
icon: Building2,
title: 'Cafetería en Cadena',
description: 'Múltiples ubicaciones con productos estandarizados',
color: 'indigo',
bgColor: 'bg-indigo-50',
borderColor: 'border-indigo-200',
textColor: 'text-indigo-900',
businessType: 'coffee_shop'
},
// Legacy fallbacks
production: {
@@ -282,7 +306,8 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
color: 'blue',
bgColor: 'bg-blue-50',
borderColor: 'border-blue-200',
textColor: 'text-blue-900'
textColor: 'text-blue-900',
businessType: 'bakery'
},
retail: {
icon: Store,
@@ -291,7 +316,8 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
color: 'green',
bgColor: 'bg-green-50',
borderColor: 'border-green-200',
textColor: 'text-green-900'
textColor: 'text-green-900',
businessType: 'bakery'
},
hybrid: {
icon: Settings2,
@@ -300,7 +326,8 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
color: 'purple',
bgColor: 'bg-purple-50',
borderColor: 'border-purple-200',
textColor: 'text-purple-900'
textColor: 'text-purple-900',
businessType: 'bakery'
}
};
@@ -331,12 +358,28 @@ const SmartHistoricalDataImport: React.FC<SmartHistoricalDataImportProps> = ({
</span>
</div>
<div className="flex items-center space-x-2">
<Coffee className="w-4 h-4 text-brown-500" />
<Package className="w-4 h-4 text-green-500" />
<span className="text-sm text-gray-700">
{analysis.finished_product_count} productos finales
</span>
</div>
</div>
{/* Enhanced business intelligence insights if available */}
{config.businessType === 'coffee_shop' && (
<div className="mb-4 p-3 bg-amber-100 border border-amber-200 rounded-lg">
<div className="flex items-center space-x-2 mb-2">
<Coffee className="w-4 h-4 text-amber-600" />
<span className="text-sm font-medium text-amber-800">
Negocio de Cafetería Detectado
</span>
</div>
<p className="text-xs text-amber-700">
Hemos detectado que tu negocio se enfoca principalmente en bebidas y comida ligera.
El sistema se optimizará para gestión de inventario de cafetería.
</p>
</div>
)}
{analysis.recommendations.length > 0 && (
<div>

View File

@@ -19,7 +19,7 @@ import {
} from 'lucide-react';
import { useSales } from '../../api/hooks/useSales';
import { useInventory } from '../../api/hooks/useInventory';
import { useInventory, useInventoryProducts } from '../../api/hooks/useInventory';
import { useAuth } from '../../api/hooks/useAuth';
import Card from '../ui/Card';
@@ -37,10 +37,13 @@ const SalesAnalyticsDashboard: React.FC = () => {
const {
getSalesAnalytics,
getSalesData,
getProductsList,
isLoading: salesLoading,
error: salesError
} = useSales();
const {
getProductsList
} = useInventoryProducts();
const {
items: products,