327 lines
13 KiB
TypeScript
327 lines
13 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
|||
|
|
import { useTranslation } from 'react-i18next';
|
|||
|
|
import { Sparkles, PenTool, ArrowRight } from 'lucide-react';
|
|||
|
|
import Button from '../../../ui/Button/Button';
|
|||
|
|
import Card from '../../../ui/Card/Card';
|
|||
|
|
|
|||
|
|
export interface DataSourceChoiceStepProps {
|
|||
|
|
onUpdate?: (data: { dataSource: 'ai-assisted' | 'manual' }) => void;
|
|||
|
|
onComplete?: () => void;
|
|||
|
|
initialData?: {
|
|||
|
|
dataSource?: 'ai-assisted' | 'manual';
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface DataSourceOption {
|
|||
|
|
id: 'ai-assisted' | 'manual';
|
|||
|
|
icon: React.ReactNode;
|
|||
|
|
title: string;
|
|||
|
|
description: string;
|
|||
|
|
benefits: string[];
|
|||
|
|
idealFor: string[];
|
|||
|
|
estimatedTime: string;
|
|||
|
|
color: string;
|
|||
|
|
gradient: string;
|
|||
|
|
badge?: string;
|
|||
|
|
badgeColor?: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const DataSourceChoiceStep: React.FC<DataSourceChoiceStepProps> = ({
|
|||
|
|
onUpdate,
|
|||
|
|
onComplete,
|
|||
|
|
initialData,
|
|||
|
|
}) => {
|
|||
|
|
const { t } = useTranslation();
|
|||
|
|
const [selectedSource, setSelectedSource] = useState<'ai-assisted' | 'manual' | null>(
|
|||
|
|
initialData?.dataSource || null
|
|||
|
|
);
|
|||
|
|
const [hoveredSource, setHoveredSource] = useState<string | null>(null);
|
|||
|
|
|
|||
|
|
const dataSourceOptions: DataSourceOption[] = [
|
|||
|
|
{
|
|||
|
|
id: 'ai-assisted',
|
|||
|
|
icon: <Sparkles className="w-12 h-12" />,
|
|||
|
|
title: t('onboarding:data_source.ai_assisted.title', 'Configuración Inteligente con IA'),
|
|||
|
|
description: t(
|
|||
|
|
'onboarding:data_source.ai_assisted.description',
|
|||
|
|
'Sube tus datos de ventas históricos y nuestra IA te ayudará a configurar automáticamente tu inventario'
|
|||
|
|
),
|
|||
|
|
benefits: [
|
|||
|
|
t('onboarding:data_source.ai_assisted.benefit1', '⚡ Configuración automática de productos'),
|
|||
|
|
t('onboarding:data_source.ai_assisted.benefit2', '🎯 Clasificación inteligente por categorías'),
|
|||
|
|
t('onboarding:data_source.ai_assisted.benefit3', '💰 Análisis de costos y precios históricos'),
|
|||
|
|
t('onboarding:data_source.ai_assisted.benefit4', '📊 Recomendaciones basadas en patrones de venta'),
|
|||
|
|
],
|
|||
|
|
idealFor: [
|
|||
|
|
t('onboarding:data_source.ai_assisted.ideal1', 'Panaderías con historial de ventas'),
|
|||
|
|
t('onboarding:data_source.ai_assisted.ideal2', 'Migración desde otro sistema'),
|
|||
|
|
t('onboarding:data_source.ai_assisted.ideal3', 'Necesitas configurar rápido'),
|
|||
|
|
],
|
|||
|
|
estimatedTime: t('onboarding:data_source.ai_assisted.time', '5-10 minutos'),
|
|||
|
|
color: 'text-purple-600',
|
|||
|
|
gradient: 'bg-gradient-to-br from-purple-50 to-pink-50',
|
|||
|
|
badge: t('onboarding:data_source.ai_assisted.badge', 'Recomendado'),
|
|||
|
|
badgeColor: 'bg-purple-100 text-purple-700',
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 'manual',
|
|||
|
|
icon: <PenTool className="w-12 h-12" />,
|
|||
|
|
title: t('onboarding:data_source.manual.title', 'Configuración Manual Paso a Paso'),
|
|||
|
|
description: t(
|
|||
|
|
'onboarding:data_source.manual.description',
|
|||
|
|
'Configura tu panadería desde cero ingresando cada detalle manualmente'
|
|||
|
|
),
|
|||
|
|
benefits: [
|
|||
|
|
t('onboarding:data_source.manual.benefit1', '🎯 Control total sobre cada detalle'),
|
|||
|
|
t('onboarding:data_source.manual.benefit2', '📝 Perfecto para comenzar desde cero'),
|
|||
|
|
t('onboarding:data_source.manual.benefit3', '🧩 Personalización completa'),
|
|||
|
|
t('onboarding:data_source.manual.benefit4', '✨ Sin necesidad de datos históricos'),
|
|||
|
|
],
|
|||
|
|
idealFor: [
|
|||
|
|
t('onboarding:data_source.manual.ideal1', 'Panaderías nuevas sin historial'),
|
|||
|
|
t('onboarding:data_source.manual.ideal2', 'Prefieres control manual total'),
|
|||
|
|
t('onboarding:data_source.manual.ideal3', 'Configuración muy específica'),
|
|||
|
|
],
|
|||
|
|
estimatedTime: t('onboarding:data_source.manual.time', '15-20 minutos'),
|
|||
|
|
color: 'text-blue-600',
|
|||
|
|
gradient: 'bg-gradient-to-br from-blue-50 to-cyan-50',
|
|||
|
|
},
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const handleSelectSource = (sourceId: 'ai-assisted' | 'manual') => {
|
|||
|
|
setSelectedSource(sourceId);
|
|||
|
|
onUpdate?.({ dataSource: sourceId });
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleContinue = () => {
|
|||
|
|
if (selectedSource) {
|
|||
|
|
onComplete?.();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="max-w-5xl mx-auto p-6 space-y-8">
|
|||
|
|
{/* Header */}
|
|||
|
|
<div className="text-center space-y-3">
|
|||
|
|
<h1 className="text-3xl font-bold text-text-primary">
|
|||
|
|
{t('onboarding:data_source.title', '¿Cómo prefieres configurar tu panadería?')}
|
|||
|
|
</h1>
|
|||
|
|
<p className="text-lg text-text-secondary max-w-2xl mx-auto">
|
|||
|
|
{t(
|
|||
|
|
'onboarding:data_source.subtitle',
|
|||
|
|
'Elige el método que mejor se adapte a tu situación actual'
|
|||
|
|
)}
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Data Source Options */}
|
|||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|||
|
|
{dataSourceOptions.map((option) => {
|
|||
|
|
const isSelected = selectedSource === option.id;
|
|||
|
|
const isHovered = hoveredSource === option.id;
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Card
|
|||
|
|
key={option.id}
|
|||
|
|
className={`
|
|||
|
|
relative cursor-pointer transition-all duration-300 overflow-hidden
|
|||
|
|
${isSelected ? 'ring-4 ring-primary-500 shadow-2xl scale-105' : 'hover:shadow-xl hover:scale-102'}
|
|||
|
|
${isHovered && !isSelected ? 'shadow-lg' : ''}
|
|||
|
|
`}
|
|||
|
|
onClick={() => handleSelectSource(option.id)}
|
|||
|
|
onMouseEnter={() => setHoveredSource(option.id)}
|
|||
|
|
onMouseLeave={() => setHoveredSource(null)}
|
|||
|
|
>
|
|||
|
|
{/* Badge */}
|
|||
|
|
{option.badge && (
|
|||
|
|
<div className="absolute top-4 right-4 z-10">
|
|||
|
|
<span className={`text-xs px-3 py-1 rounded-full font-semibold ${option.badgeColor}`}>
|
|||
|
|
{option.badge}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{/* Selection Indicator */}
|
|||
|
|
{isSelected && (
|
|||
|
|
<div className="absolute top-4 left-4 z-10">
|
|||
|
|
<div className="w-6 h-6 bg-primary-500 rounded-full flex items-center justify-center shadow-lg animate-scale-in">
|
|||
|
|
<span className="text-white text-sm">✓</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{/* Gradient Background */}
|
|||
|
|
<div className={`absolute inset-0 ${option.gradient} opacity-40 transition-opacity ${isSelected ? 'opacity-60' : ''}`} />
|
|||
|
|
|
|||
|
|
{/* Content */}
|
|||
|
|
<div className="relative p-6 space-y-4">
|
|||
|
|
{/* Icon & Title */}
|
|||
|
|
<div className="space-y-3">
|
|||
|
|
<div className={option.color}>
|
|||
|
|
{option.icon}
|
|||
|
|
</div>
|
|||
|
|
<h3 className="text-xl font-bold text-text-primary">
|
|||
|
|
{option.title}
|
|||
|
|
</h3>
|
|||
|
|
<p className="text-sm text-text-secondary leading-relaxed">
|
|||
|
|
{option.description}
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Benefits */}
|
|||
|
|
<div className="space-y-2 pt-2">
|
|||
|
|
<h4 className="text-xs font-semibold text-text-secondary uppercase tracking-wide">
|
|||
|
|
{t('onboarding:data_source.benefits_label', 'Beneficios')}
|
|||
|
|
</h4>
|
|||
|
|
<ul className="space-y-1.5">
|
|||
|
|
{option.benefits.map((benefit, index) => (
|
|||
|
|
<li
|
|||
|
|
key={index}
|
|||
|
|
className="text-sm text-text-primary"
|
|||
|
|
>
|
|||
|
|
{benefit}
|
|||
|
|
</li>
|
|||
|
|
))}
|
|||
|
|
</ul>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Ideal For */}
|
|||
|
|
<div className="space-y-2 pt-2 border-t border-border-primary">
|
|||
|
|
<h4 className="text-xs font-semibold text-text-secondary uppercase tracking-wide">
|
|||
|
|
{t('onboarding:data_source.ideal_for_label', 'Ideal para')}
|
|||
|
|
</h4>
|
|||
|
|
<ul className="space-y-1">
|
|||
|
|
{option.idealFor.map((item, index) => (
|
|||
|
|
<li
|
|||
|
|
key={index}
|
|||
|
|
className="text-xs text-text-secondary flex items-start gap-2"
|
|||
|
|
>
|
|||
|
|
<span className="text-primary-500 mt-0.5">•</span>
|
|||
|
|
<span>{item}</span>
|
|||
|
|
</li>
|
|||
|
|
))}
|
|||
|
|
</ul>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Estimated Time */}
|
|||
|
|
<div className="pt-2">
|
|||
|
|
<div className="inline-flex items-center gap-2 px-3 py-1.5 bg-bg-secondary rounded-lg">
|
|||
|
|
<span className="text-xs text-text-secondary">
|
|||
|
|
⏱️ {t('onboarding:data_source.estimated_time_label', 'Tiempo estimado')}:
|
|||
|
|
</span>
|
|||
|
|
<span className="text-xs font-semibold text-text-primary">
|
|||
|
|
{option.estimatedTime}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</Card>
|
|||
|
|
);
|
|||
|
|
})}
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Additional Info Based on Selection */}
|
|||
|
|
{selectedSource === 'ai-assisted' && (
|
|||
|
|
<div className="p-6 bg-purple-50 border border-purple-200 rounded-lg animate-fade-in">
|
|||
|
|
<div className="flex items-start gap-4">
|
|||
|
|
<div className="flex-shrink-0">
|
|||
|
|
<Sparkles className="w-8 h-8 text-purple-600" />
|
|||
|
|
</div>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<h4 className="font-semibold text-text-primary">
|
|||
|
|
{t('onboarding:data_source.ai_info_title', '¿Qué necesitas para la configuración con IA?')}
|
|||
|
|
</h4>
|
|||
|
|
<ul className="space-y-1 text-sm text-text-secondary">
|
|||
|
|
<li className="flex items-start gap-2">
|
|||
|
|
<span className="text-purple-600">•</span>
|
|||
|
|
<span>
|
|||
|
|
{t('onboarding:data_source.ai_info1', 'Archivo de ventas (CSV, Excel o JSON)')}
|
|||
|
|
</span>
|
|||
|
|
</li>
|
|||
|
|
<li className="flex items-start gap-2">
|
|||
|
|
<span className="text-purple-600">•</span>
|
|||
|
|
<span>
|
|||
|
|
{t('onboarding:data_source.ai_info2', 'Datos de al menos 1-3 meses (recomendado)')}
|
|||
|
|
</span>
|
|||
|
|
</li>
|
|||
|
|
<li className="flex items-start gap-2">
|
|||
|
|
<span className="text-purple-600">•</span>
|
|||
|
|
<span>
|
|||
|
|
{t('onboarding:data_source.ai_info3', 'Información de productos, precios y cantidades')}
|
|||
|
|
</span>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{selectedSource === 'manual' && (
|
|||
|
|
<div className="p-6 bg-blue-50 border border-blue-200 rounded-lg animate-fade-in">
|
|||
|
|
<div className="flex items-start gap-4">
|
|||
|
|
<div className="flex-shrink-0">
|
|||
|
|
<PenTool className="w-8 h-8 text-blue-600" />
|
|||
|
|
</div>
|
|||
|
|
<div className="space-y-2">
|
|||
|
|
<h4 className="font-semibold text-text-primary">
|
|||
|
|
{t('onboarding:data_source.manual_info_title', '¿Qué configuraremos paso a paso?')}
|
|||
|
|
</h4>
|
|||
|
|
<ul className="space-y-1 text-sm text-text-secondary">
|
|||
|
|
<li className="flex items-start gap-2">
|
|||
|
|
<span className="text-blue-600">•</span>
|
|||
|
|
<span>
|
|||
|
|
{t('onboarding:data_source.manual_info1', 'Proveedores y sus datos de contacto')}
|
|||
|
|
</span>
|
|||
|
|
</li>
|
|||
|
|
<li className="flex items-start gap-2">
|
|||
|
|
<span className="text-blue-600">•</span>
|
|||
|
|
<span>
|
|||
|
|
{t('onboarding:data_source.manual_info2', 'Inventario de ingredientes y productos')}
|
|||
|
|
</span>
|
|||
|
|
</li>
|
|||
|
|
<li className="flex items-start gap-2">
|
|||
|
|
<span className="text-blue-600">•</span>
|
|||
|
|
<span>
|
|||
|
|
{t('onboarding:data_source.manual_info3', 'Recetas o procesos de producción')}
|
|||
|
|
</span>
|
|||
|
|
</li>
|
|||
|
|
<li className="flex items-start gap-2">
|
|||
|
|
<span className="text-blue-600">•</span>
|
|||
|
|
<span>
|
|||
|
|
{t('onboarding:data_source.manual_info4', 'Estándares de calidad y equipo (opcional)')}
|
|||
|
|
</span>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{/* Continue Button */}
|
|||
|
|
<div className="flex justify-center pt-4">
|
|||
|
|
<Button
|
|||
|
|
onClick={handleContinue}
|
|||
|
|
disabled={!selectedSource}
|
|||
|
|
size="lg"
|
|||
|
|
className="min-w-[200px] gap-2"
|
|||
|
|
>
|
|||
|
|
{t('onboarding:data_source.continue_button', 'Continuar')}
|
|||
|
|
<ArrowRight className="w-5 h-5" />
|
|||
|
|
</Button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Help Text */}
|
|||
|
|
<div className="text-center">
|
|||
|
|
<p className="text-sm text-text-secondary">
|
|||
|
|
{t(
|
|||
|
|
'onboarding:data_source.help_text',
|
|||
|
|
'💡 Puedes cambiar entre métodos en cualquier momento durante la configuración'
|
|||
|
|
)}
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default DataSourceChoiceStep;
|