2025-10-17 18:14:28 +02:00
|
|
|
import React, { useState } from 'react';
|
|
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
|
import { PublicLayout } from '../../components/layout';
|
|
|
|
|
import {
|
|
|
|
|
FileText,
|
|
|
|
|
BookOpen,
|
|
|
|
|
Rocket,
|
|
|
|
|
Package,
|
|
|
|
|
BarChart3,
|
|
|
|
|
Settings,
|
|
|
|
|
Users,
|
|
|
|
|
Shield,
|
|
|
|
|
CreditCard,
|
|
|
|
|
HelpCircle,
|
|
|
|
|
ChevronRight,
|
|
|
|
|
PlayCircle,
|
|
|
|
|
CheckCircle2,
|
|
|
|
|
AlertCircle,
|
|
|
|
|
Info,
|
|
|
|
|
Download,
|
|
|
|
|
ExternalLink
|
|
|
|
|
} from 'lucide-react';
|
|
|
|
|
|
|
|
|
|
interface DocSection {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
icon: React.ComponentType<{ className?: string }>;
|
|
|
|
|
articles: DocArticle[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface DocArticle {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
readTime: string;
|
|
|
|
|
difficulty: 'beginner' | 'intermediate' | 'advanced';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DocumentationPage: React.FC = () => {
|
2025-11-18 12:07:37 +00:00
|
|
|
const { t } = useTranslation('help');
|
2025-10-17 18:14:28 +02:00
|
|
|
const [activeSection, setActiveSection] = useState<string>('getting-started');
|
2025-11-18 12:35:22 +00:00
|
|
|
const [selectedArticle, setSelectedArticle] = useState<{ sectionId: string; articleId: string } | null>(null);
|
2025-10-17 18:14:28 +02:00
|
|
|
|
|
|
|
|
const sections: DocSection[] = [
|
|
|
|
|
{
|
|
|
|
|
id: 'getting-started',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('categories.gettingStarted.title'),
|
|
|
|
|
description: t('categories.gettingStarted.description'),
|
2025-10-17 18:14:28 +02:00
|
|
|
icon: Rocket,
|
|
|
|
|
articles: [
|
|
|
|
|
{
|
|
|
|
|
id: 'quick-start',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.gettingStarted.quickStart.title'),
|
|
|
|
|
description: t('articles.gettingStarted.quickStart.description'),
|
|
|
|
|
readTime: `${t('articles.gettingStarted.quickStart.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'import-data',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.gettingStarted.importData.title'),
|
|
|
|
|
description: t('articles.gettingStarted.importData.description'),
|
|
|
|
|
readTime: `${t('articles.gettingStarted.importData.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'products-catalog',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.gettingStarted.productsCatalog.title'),
|
|
|
|
|
description: t('articles.gettingStarted.productsCatalog.description'),
|
|
|
|
|
readTime: `${t('articles.gettingStarted.productsCatalog.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'first-prediction',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.gettingStarted.firstPrediction.title'),
|
|
|
|
|
description: t('articles.gettingStarted.firstPrediction.description'),
|
|
|
|
|
readTime: `${t('articles.gettingStarted.firstPrediction.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'features',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('categories.features.title'),
|
|
|
|
|
description: t('categories.features.description'),
|
2025-10-17 18:14:28 +02:00
|
|
|
icon: Package,
|
|
|
|
|
articles: [
|
|
|
|
|
{
|
|
|
|
|
id: 'demand-forecasting',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.features.demandForecasting.title'),
|
|
|
|
|
description: t('articles.features.demandForecasting.description'),
|
|
|
|
|
readTime: `${t('articles.features.demandForecasting.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'production-planning',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.features.productionPlanning.title'),
|
|
|
|
|
description: t('articles.features.productionPlanning.description'),
|
|
|
|
|
readTime: `${t('articles.features.productionPlanning.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'inventory-management',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.features.inventoryManagement.title'),
|
|
|
|
|
description: t('articles.features.inventoryManagement.description'),
|
|
|
|
|
readTime: `${t('articles.features.inventoryManagement.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'pos-integration',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.features.posIntegration.title'),
|
|
|
|
|
description: t('articles.features.posIntegration.description'),
|
|
|
|
|
readTime: `${t('articles.features.posIntegration.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'waste-tracking',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.features.wasteTracking.title'),
|
|
|
|
|
description: t('articles.features.wasteTracking.description'),
|
|
|
|
|
readTime: `${t('articles.features.wasteTracking.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'analytics',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('categories.analytics.title'),
|
|
|
|
|
description: t('categories.analytics.description'),
|
2025-10-17 18:14:28 +02:00
|
|
|
icon: BarChart3,
|
|
|
|
|
articles: [
|
|
|
|
|
{
|
|
|
|
|
id: 'dashboard-overview',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.analytics.dashboardOverview.title'),
|
|
|
|
|
description: t('articles.analytics.dashboardOverview.description'),
|
|
|
|
|
readTime: `${t('articles.analytics.dashboardOverview.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'reports',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.analytics.reports.title'),
|
|
|
|
|
description: t('articles.analytics.reports.description'),
|
|
|
|
|
readTime: `${t('articles.analytics.reports.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'ai-insights',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.analytics.aiInsights.title'),
|
|
|
|
|
description: t('articles.analytics.aiInsights.description'),
|
|
|
|
|
readTime: `${t('articles.analytics.aiInsights.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'advanced',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'performance-metrics',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('articles.analytics.performanceMetrics.title'),
|
|
|
|
|
description: t('articles.analytics.performanceMetrics.description'),
|
|
|
|
|
readTime: `${t('articles.analytics.performanceMetrics.readTime')} ${t('docs.readTime')}`,
|
2025-10-17 18:14:28 +02:00
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'account',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('categories.account.title'),
|
|
|
|
|
description: t('categories.account.description'),
|
2025-10-17 18:14:28 +02:00
|
|
|
icon: Settings,
|
|
|
|
|
articles: [
|
|
|
|
|
{
|
|
|
|
|
id: 'profile-settings',
|
|
|
|
|
title: 'Configuración de Perfil',
|
|
|
|
|
description: 'Actualiza tu información personal y preferencias',
|
|
|
|
|
readTime: '4 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'team-management',
|
|
|
|
|
title: 'Gestionar Equipo',
|
|
|
|
|
description: 'Añade miembros, asigna roles y permisos',
|
|
|
|
|
readTime: '7 min',
|
|
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'notifications',
|
|
|
|
|
title: 'Notificaciones y Alertas',
|
|
|
|
|
description: 'Configura cómo y cuándo recibir avisos',
|
|
|
|
|
readTime: '5 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'integrations',
|
|
|
|
|
title: 'Integraciones',
|
|
|
|
|
description: 'Conecta con TPV, contabilidad y otras herramientas',
|
|
|
|
|
readTime: '10 min',
|
|
|
|
|
difficulty: 'advanced',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'billing',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('categories.billing.title'),
|
|
|
|
|
description: t('categories.billing.description'),
|
2025-10-17 18:14:28 +02:00
|
|
|
icon: CreditCard,
|
|
|
|
|
articles: [
|
|
|
|
|
{
|
|
|
|
|
id: 'pricing-plans',
|
|
|
|
|
title: 'Planes y Precios',
|
|
|
|
|
description: 'Compara características de cada plan',
|
|
|
|
|
readTime: '6 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'payment-methods',
|
|
|
|
|
title: 'Métodos de Pago',
|
|
|
|
|
description: 'Añade, modifica o elimina tarjetas',
|
|
|
|
|
readTime: '4 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'invoices',
|
|
|
|
|
title: 'Facturas y Recibos',
|
|
|
|
|
description: 'Descarga y gestiona tu historial de facturación',
|
|
|
|
|
readTime: '5 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'cancel-subscription',
|
|
|
|
|
title: 'Cancelar o Pausar Suscripción',
|
|
|
|
|
description: 'Cómo proceder si necesitas hacer una pausa',
|
|
|
|
|
readTime: '3 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'privacy',
|
2025-11-18 12:07:37 +00:00
|
|
|
title: t('categories.privacy.title'),
|
|
|
|
|
description: t('categories.privacy.description'),
|
2025-10-17 18:14:28 +02:00
|
|
|
icon: Shield,
|
|
|
|
|
articles: [
|
|
|
|
|
{
|
|
|
|
|
id: 'gdpr-compliance',
|
|
|
|
|
title: 'Cumplimiento RGPD',
|
|
|
|
|
description: 'Cómo protegemos tus datos según normativa europea',
|
|
|
|
|
readTime: '10 min',
|
|
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'data-export',
|
|
|
|
|
title: 'Exportar Tus Datos',
|
|
|
|
|
description: 'Descarga toda tu información en cualquier momento',
|
|
|
|
|
readTime: '5 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'data-deletion',
|
|
|
|
|
title: 'Eliminar Tu Cuenta',
|
|
|
|
|
description: 'Procedimiento para borrar permanentemente tus datos',
|
|
|
|
|
readTime: '6 min',
|
|
|
|
|
difficulty: 'beginner',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'security-best-practices',
|
|
|
|
|
title: 'Mejores Prácticas de Seguridad',
|
|
|
|
|
description: 'Protege tu cuenta con 2FA y contraseñas fuertes',
|
|
|
|
|
readTime: '8 min',
|
|
|
|
|
difficulty: 'intermediate',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const activeContent = sections.find((s) => s.id === activeSection);
|
|
|
|
|
|
|
|
|
|
const getDifficultyColor = (difficulty: string) => {
|
|
|
|
|
switch (difficulty) {
|
|
|
|
|
case 'beginner':
|
|
|
|
|
return 'text-green-600 dark:text-green-400';
|
|
|
|
|
case 'intermediate':
|
|
|
|
|
return 'text-amber-600 dark:text-amber-400';
|
|
|
|
|
case 'advanced':
|
|
|
|
|
return 'text-red-600 dark:text-red-400';
|
|
|
|
|
default:
|
|
|
|
|
return 'text-[var(--text-tertiary)]';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getDifficultyLabel = (difficulty: string) => {
|
2025-11-18 12:07:37 +00:00
|
|
|
return t(`difficulty.${difficulty}` as any) || difficulty;
|
2025-10-17 18:14:28 +02:00
|
|
|
};
|
|
|
|
|
|
2025-11-18 12:35:22 +00:00
|
|
|
const getCategoryKey = (sectionId: string): string => {
|
|
|
|
|
const categoryMap: Record<string, string> = {
|
|
|
|
|
'getting-started': 'gettingStarted',
|
|
|
|
|
'features': 'features',
|
|
|
|
|
'analytics': 'analytics',
|
|
|
|
|
'account': 'account',
|
|
|
|
|
'billing': 'billing',
|
|
|
|
|
'privacy': 'privacy',
|
|
|
|
|
};
|
|
|
|
|
return categoryMap[sectionId] || sectionId;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getArticleKey = (articleId: string): string => {
|
|
|
|
|
const articleMap: Record<string, string> = {
|
|
|
|
|
'quick-start': 'quickStart',
|
|
|
|
|
'import-data': 'importData',
|
|
|
|
|
'products-catalog': 'productsCatalog',
|
|
|
|
|
'first-prediction': 'firstPrediction',
|
|
|
|
|
'demand-forecasting': 'demandForecasting',
|
|
|
|
|
'production-planning': 'productionPlanning',
|
|
|
|
|
'inventory-management': 'inventoryManagement',
|
|
|
|
|
'pos-integration': 'posIntegration',
|
|
|
|
|
'waste-tracking': 'wasteTracking',
|
|
|
|
|
'dashboard-overview': 'dashboardOverview',
|
|
|
|
|
'reports': 'reports',
|
|
|
|
|
'ai-insights': 'aiInsights',
|
|
|
|
|
'performance-metrics': 'performanceMetrics',
|
|
|
|
|
};
|
|
|
|
|
return articleMap[articleId] || articleId;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleArticleClick = (sectionId: string, articleId: string) => {
|
|
|
|
|
setSelectedArticle({ sectionId, articleId });
|
|
|
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleBackToList = () => {
|
|
|
|
|
setSelectedArticle(null);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const renderArticleContent = () => {
|
|
|
|
|
if (!selectedArticle) return null;
|
|
|
|
|
|
|
|
|
|
const categoryKey = getCategoryKey(selectedArticle.sectionId);
|
|
|
|
|
const articleKey = getArticleKey(selectedArticle.articleId);
|
|
|
|
|
const contentPath = `articles.${categoryKey}.${articleKey}.content`;
|
|
|
|
|
|
|
|
|
|
const content: any = t(contentPath, { returnObjects: true });
|
|
|
|
|
const article = sections
|
|
|
|
|
.find((s) => s.id === selectedArticle.sectionId)
|
|
|
|
|
?.articles.find((a) => a.id === selectedArticle.articleId);
|
|
|
|
|
|
|
|
|
|
if (!article || !content) return null;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
{/* Back Button */}
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleBackToList}
|
|
|
|
|
className="mb-6 flex items-center gap-2 text-[var(--color-primary)] hover:underline"
|
|
|
|
|
>
|
|
|
|
|
<ChevronRight className="w-5 h-5 transform rotate-180" />
|
|
|
|
|
<span>{t('docs.backToHelp')}</span>
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
{/* Article Header */}
|
|
|
|
|
<div className="mb-8 pb-8 border-b border-[var(--border-primary)]">
|
|
|
|
|
<h1 className="text-4xl font-extrabold text-[var(--text-primary)] mb-4">
|
|
|
|
|
{article.title}
|
|
|
|
|
</h1>
|
|
|
|
|
<p className="text-xl text-[var(--text-secondary)] mb-4">{article.description}</p>
|
|
|
|
|
<div className="flex items-center gap-4 text-sm">
|
|
|
|
|
<span className="flex items-center gap-1 text-[var(--text-tertiary)]">
|
|
|
|
|
<PlayCircle className="w-4 h-4" />
|
|
|
|
|
{article.readTime}
|
|
|
|
|
</span>
|
|
|
|
|
<span className={`font-medium ${getDifficultyColor(article.difficulty)}`}>
|
|
|
|
|
{getDifficultyLabel(article.difficulty)}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Article Content */}
|
|
|
|
|
<div className="prose prose-lg dark:prose-invert max-w-none">
|
|
|
|
|
{/* Intro */}
|
|
|
|
|
{content.intro && (
|
|
|
|
|
<div className="bg-[var(--color-primary)]/5 border-l-4 border-[var(--color-primary)] p-6 rounded-r-xl mb-8">
|
|
|
|
|
<p className="text-[var(--text-primary)] text-lg leading-relaxed m-0">
|
|
|
|
|
{content.intro}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Steps */}
|
|
|
|
|
{content.steps && Array.isArray(content.steps) && (
|
|
|
|
|
<div className="space-y-6 mb-8">
|
|
|
|
|
{content.steps.map((step: any, index: number) => (
|
|
|
|
|
<div
|
|
|
|
|
key={index}
|
|
|
|
|
className="bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)]"
|
|
|
|
|
>
|
|
|
|
|
<h3 className="text-xl font-bold text-[var(--text-primary)] mb-3 mt-0">
|
|
|
|
|
{step.title}
|
|
|
|
|
</h3>
|
|
|
|
|
<p className="text-[var(--text-secondary)] leading-relaxed m-0">
|
|
|
|
|
{step.description}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Tips */}
|
|
|
|
|
{content.tips && Array.isArray(content.tips) && content.tips.length > 0 && (
|
|
|
|
|
<div className="bg-amber-50 dark:bg-amber-900/20 border-2 border-amber-200 dark:border-amber-800 rounded-xl p-6 mb-8">
|
|
|
|
|
<h3 className="text-xl font-bold text-[var(--text-primary)] mb-4 mt-0 flex items-center gap-2">
|
|
|
|
|
<Info className="w-6 h-6 text-amber-600" />
|
|
|
|
|
<span>Consejos Útiles</span>
|
|
|
|
|
</h3>
|
|
|
|
|
<ul className="space-y-2 m-0 pl-0 list-none">
|
|
|
|
|
{content.tips.map((tip: string, index: number) => (
|
|
|
|
|
<li key={index} className="flex items-start gap-3">
|
|
|
|
|
<CheckCircle2 className="w-5 h-5 text-amber-600 flex-shrink-0 mt-0.5" />
|
|
|
|
|
<span className="text-[var(--text-secondary)]">{tip}</span>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Conclusion */}
|
|
|
|
|
{content.conclusion && (
|
|
|
|
|
<div className="bg-green-50 dark:bg-green-900/20 border-l-4 border-green-600 p-6 rounded-r-xl">
|
|
|
|
|
<p className="text-[var(--text-primary)] leading-relaxed m-0">
|
|
|
|
|
{content.conclusion}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Back to List Button */}
|
|
|
|
|
<div className="mt-12 pt-8 border-t border-[var(--border-primary)]">
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleBackToList}
|
|
|
|
|
className="flex items-center gap-2 px-6 py-3 bg-[var(--color-primary)] text-white rounded-xl font-bold hover:shadow-xl transition-all"
|
|
|
|
|
>
|
|
|
|
|
<ChevronRight className="w-5 h-5 transform rotate-180" />
|
|
|
|
|
<span>Volver a la Lista</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-10-17 18:14:28 +02:00
|
|
|
return (
|
|
|
|
|
<PublicLayout
|
|
|
|
|
variant="default"
|
2025-11-06 18:39:20 +00:00
|
|
|
contentPadding="md"
|
2025-10-17 18:14:28 +02:00
|
|
|
headerProps={{
|
|
|
|
|
showThemeToggle: true,
|
|
|
|
|
showAuthButtons: true,
|
|
|
|
|
showLanguageSelector: true,
|
|
|
|
|
variant: 'default',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{/* Hero Section */}
|
|
|
|
|
<section className="bg-gradient-to-br from-[var(--bg-primary)] via-[var(--bg-secondary)] to-[var(--color-primary)]/5 py-20">
|
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
|
|
|
<div className="text-center max-w-4xl mx-auto">
|
|
|
|
|
<div className="inline-flex items-center gap-2 bg-[var(--color-primary)]/10 text-[var(--color-primary)] px-4 py-2 rounded-full text-sm font-medium mb-6">
|
|
|
|
|
<FileText className="w-4 h-4" />
|
2025-11-18 12:07:37 +00:00
|
|
|
<span>{t('docs.subtitle')}</span>
|
2025-10-17 18:14:28 +02:00
|
|
|
</div>
|
|
|
|
|
<h1 className="text-4xl lg:text-6xl font-extrabold text-[var(--text-primary)] mb-6">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.title')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h1>
|
|
|
|
|
<p className="text-xl text-[var(--text-secondary)] leading-relaxed mb-8">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.description')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
{/* Quick Actions */}
|
|
|
|
|
<div className="flex flex-wrap justify-center gap-4">
|
|
|
|
|
<a
|
|
|
|
|
href="#getting-started"
|
|
|
|
|
onClick={() => setActiveSection('getting-started')}
|
|
|
|
|
className="inline-flex items-center gap-2 px-6 py-3 bg-[var(--color-primary)] text-white rounded-xl font-bold hover:shadow-xl transition-all hover:scale-105"
|
|
|
|
|
>
|
|
|
|
|
<Rocket className="w-5 h-5" />
|
2025-11-18 12:07:37 +00:00
|
|
|
<span>{t('docs.getStarted')}</span>
|
2025-10-17 18:14:28 +02:00
|
|
|
</a>
|
|
|
|
|
<Link
|
|
|
|
|
to="/help"
|
|
|
|
|
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-[var(--border-primary)] text-[var(--text-primary)] rounded-xl font-medium hover:border-[var(--color-primary)] transition-all"
|
|
|
|
|
>
|
|
|
|
|
<HelpCircle className="w-5 h-5" />
|
2025-11-18 12:07:37 +00:00
|
|
|
<span>{t('docs.backToHelp')}</span>
|
2025-10-17 18:14:28 +02:00
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
{/* Documentation Content */}
|
|
|
|
|
<section className="py-20 bg-[var(--bg-primary)]">
|
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
|
|
|
<div className="grid lg:grid-cols-4 gap-8">
|
|
|
|
|
{/* Sidebar Navigation */}
|
|
|
|
|
<div className="lg:col-span-1">
|
|
|
|
|
<div className="sticky top-8">
|
|
|
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-4">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.sectionsTitle')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h3>
|
|
|
|
|
<nav className="space-y-2">
|
|
|
|
|
{sections.map((section) => (
|
|
|
|
|
<button
|
|
|
|
|
key={section.id}
|
2025-11-18 12:35:22 +00:00
|
|
|
onClick={() => {
|
|
|
|
|
setActiveSection(section.id);
|
|
|
|
|
setSelectedArticle(null);
|
|
|
|
|
}}
|
2025-10-17 18:14:28 +02:00
|
|
|
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl text-left transition-all ${
|
|
|
|
|
activeSection === section.id
|
|
|
|
|
? 'bg-[var(--color-primary)] text-white'
|
|
|
|
|
: 'bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--color-primary)]/10'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<section.icon className="w-5 h-5 flex-shrink-0" />
|
|
|
|
|
<div className="flex-1 min-w-0">
|
|
|
|
|
<div className="font-medium truncate">{section.title}</div>
|
|
|
|
|
<div
|
|
|
|
|
className={`text-xs ${
|
|
|
|
|
activeSection === section.id ? 'text-white/80' : 'text-[var(--text-tertiary)]'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
2025-11-18 12:07:37 +00:00
|
|
|
{section.articles.length} {t('docs.articlesCount')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
{/* Quick Links */}
|
|
|
|
|
<div className="mt-8 p-4 bg-[var(--bg-secondary)] rounded-xl border border-[var(--border-primary)]">
|
|
|
|
|
<h4 className="font-bold text-[var(--text-primary)] mb-3 text-sm">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.quickLinks')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h4>
|
|
|
|
|
<div className="space-y-2 text-sm">
|
|
|
|
|
<Link
|
|
|
|
|
to="/help"
|
|
|
|
|
className="flex items-center gap-2 text-[var(--text-secondary)] hover:text-[var(--color-primary)] transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<HelpCircle className="w-4 h-4" />
|
2025-11-18 12:07:37 +00:00
|
|
|
<span>{t('docs.backToHelp')}</span>
|
2025-10-17 18:14:28 +02:00
|
|
|
</Link>
|
|
|
|
|
<Link
|
|
|
|
|
to="/help/support"
|
|
|
|
|
className="flex items-center gap-2 text-[var(--text-secondary)] hover:text-[var(--color-primary)] transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<ExternalLink className="w-4 h-4" />
|
2025-11-18 12:07:37 +00:00
|
|
|
<span>{t('docs.contactSupport')}</span>
|
2025-10-17 18:14:28 +02:00
|
|
|
</Link>
|
|
|
|
|
<a
|
|
|
|
|
href="#"
|
|
|
|
|
className="flex items-center gap-2 text-[var(--text-secondary)] hover:text-[var(--color-primary)] transition-colors"
|
|
|
|
|
>
|
|
|
|
|
<Download className="w-4 h-4" />
|
2025-11-18 12:07:37 +00:00
|
|
|
<span>{t('docs.downloadPdf')}</span>
|
2025-10-17 18:14:28 +02:00
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Main Content */}
|
|
|
|
|
<div className="lg:col-span-3">
|
2025-11-18 12:35:22 +00:00
|
|
|
{selectedArticle ? (
|
|
|
|
|
renderArticleContent()
|
|
|
|
|
) : (
|
|
|
|
|
activeContent && (
|
|
|
|
|
<div>
|
|
|
|
|
{/* Section Header */}
|
|
|
|
|
<div className="mb-8">
|
|
|
|
|
<div className="flex items-center gap-4 mb-4">
|
|
|
|
|
<div className="w-12 h-12 bg-[var(--color-primary)]/10 rounded-xl flex items-center justify-center">
|
|
|
|
|
<activeContent.icon className="w-6 h-6 text-[var(--color-primary)]" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<h2 className="text-3xl font-extrabold text-[var(--text-primary)]">
|
|
|
|
|
{activeContent.title}
|
|
|
|
|
</h2>
|
|
|
|
|
<p className="text-[var(--text-secondary)]">{activeContent.description}</p>
|
|
|
|
|
</div>
|
2025-10-17 18:14:28 +02:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-11-18 12:35:22 +00:00
|
|
|
{/* Articles Grid */}
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
{activeContent.articles.map((article) => (
|
|
|
|
|
<button
|
|
|
|
|
key={article.id}
|
|
|
|
|
onClick={() => handleArticleClick(activeSection, article.id)}
|
|
|
|
|
className="w-full block bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)] hover:border-[var(--color-primary)] hover:shadow-xl transition-all group text-left"
|
|
|
|
|
>
|
|
|
|
|
<div className="flex items-start justify-between gap-4">
|
|
|
|
|
<div className="flex-1">
|
|
|
|
|
<h3 className="text-xl font-bold text-[var(--text-primary)] mb-2 group-hover:text-[var(--color-primary)] transition-colors">
|
|
|
|
|
{article.title}
|
|
|
|
|
</h3>
|
|
|
|
|
<p className="text-[var(--text-secondary)] mb-4">{article.description}</p>
|
|
|
|
|
<div className="flex items-center gap-4 text-sm">
|
|
|
|
|
<span className="flex items-center gap-1 text-[var(--text-tertiary)]">
|
|
|
|
|
<PlayCircle className="w-4 h-4" />
|
|
|
|
|
{article.readTime}
|
|
|
|
|
</span>
|
|
|
|
|
<span className={`font-medium ${getDifficultyColor(article.difficulty)}`}>
|
|
|
|
|
{getDifficultyLabel(article.difficulty)}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
2025-10-17 18:14:28 +02:00
|
|
|
</div>
|
2025-11-18 12:35:22 +00:00
|
|
|
<ChevronRight className="w-6 h-6 text-[var(--text-tertiary)] group-hover:text-[var(--color-primary)] transition-colors flex-shrink-0" />
|
2025-10-17 18:14:28 +02:00
|
|
|
</div>
|
2025-11-18 12:35:22 +00:00
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2025-10-17 18:14:28 +02:00
|
|
|
</div>
|
2025-11-18 12:35:22 +00:00
|
|
|
)
|
2025-10-17 18:14:28 +02:00
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
{/* Video Tutorials */}
|
|
|
|
|
<section className="py-20 bg-[var(--bg-secondary)]">
|
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
|
|
|
<div className="text-center mb-12">
|
|
|
|
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-[var(--text-primary)] mb-4">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.videoTutorialsTitle')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h2>
|
|
|
|
|
<p className="text-xl text-[var(--text-secondary)]">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.videoTutorialsSubtitle')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid md:grid-cols-3 gap-6">
|
|
|
|
|
{[
|
|
|
|
|
{
|
|
|
|
|
title: 'Configuración Inicial',
|
|
|
|
|
duration: '5:30',
|
|
|
|
|
thumbnail: 'getting-started',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Importar Datos Históricos',
|
|
|
|
|
duration: '8:15',
|
|
|
|
|
thumbnail: 'import-data',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Tu Primera Predicción',
|
|
|
|
|
duration: '12:00',
|
|
|
|
|
thumbnail: 'first-prediction',
|
|
|
|
|
},
|
|
|
|
|
].map((video, index) => (
|
|
|
|
|
<div
|
|
|
|
|
key={index}
|
|
|
|
|
className="bg-[var(--bg-primary)] rounded-xl overflow-hidden border border-[var(--border-primary)] hover:shadow-xl transition-all group"
|
|
|
|
|
>
|
|
|
|
|
<div className="aspect-video bg-gradient-to-br from-[var(--color-primary)]/20 to-orange-600/20 flex items-center justify-center relative">
|
|
|
|
|
<PlayCircle className="w-16 h-16 text-[var(--color-primary)] group-hover:scale-110 transition-transform" />
|
|
|
|
|
<div className="absolute bottom-2 right-2 bg-black/80 text-white px-2 py-1 rounded text-xs font-medium">
|
|
|
|
|
{video.duration}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="p-4">
|
|
|
|
|
<h3 className="font-bold text-[var(--text-primary)] group-hover:text-[var(--color-primary)] transition-colors">
|
|
|
|
|
{video.title}
|
|
|
|
|
</h3>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
{/* Additional Resources */}
|
|
|
|
|
<section className="py-20 bg-[var(--bg-primary)]">
|
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
|
|
|
<div className="text-center mb-12">
|
|
|
|
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-[var(--text-primary)] mb-4">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.additionalResourcesTitle')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h2>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid md:grid-cols-3 gap-6">
|
|
|
|
|
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-2xl p-6 border-2 border-blue-200 dark:border-blue-800">
|
|
|
|
|
<Info className="w-8 h-8 text-blue-600 mb-4" />
|
|
|
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.glossary.title')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h3>
|
|
|
|
|
<p className="text-sm text-[var(--text-secondary)] mb-4">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.glossary.description')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</p>
|
|
|
|
|
<a href="#glossary" className="text-blue-600 hover:underline font-medium text-sm">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.glossary.action')} →
|
2025-10-17 18:14:28 +02:00
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-amber-50 dark:bg-amber-900/20 rounded-2xl p-6 border-2 border-amber-200 dark:border-amber-800">
|
|
|
|
|
<AlertCircle className="w-8 h-8 text-amber-600 mb-4" />
|
|
|
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.troubleshooting.title')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h3>
|
|
|
|
|
<p className="text-sm text-[var(--text-secondary)] mb-4">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.troubleshooting.description')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</p>
|
|
|
|
|
<Link to="/help" className="text-amber-600 hover:underline font-medium text-sm">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.troubleshooting.action')} →
|
2025-10-17 18:14:28 +02:00
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="bg-green-50 dark:bg-green-900/20 rounded-2xl p-6 border-2 border-green-200 dark:border-green-800">
|
|
|
|
|
<CheckCircle2 className="w-8 h-8 text-green-600 mb-4" />
|
|
|
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.bestPractices.title')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h3>
|
|
|
|
|
<p className="text-sm text-[var(--text-secondary)] mb-4">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.bestPractices.description')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</p>
|
|
|
|
|
<a href="#best-practices" className="text-green-600 hover:underline font-medium text-sm">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('resources.bestPractices.action')} →
|
2025-10-17 18:14:28 +02:00
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
{/* CTA */}
|
|
|
|
|
<section className="py-20 bg-gradient-to-r from-[var(--color-primary)] to-orange-600">
|
|
|
|
|
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
|
|
|
|
<h2 className="text-3xl lg:text-4xl font-bold text-white mb-6">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.ctaTitle')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</h2>
|
|
|
|
|
<p className="text-xl text-white/90 mb-8">
|
2025-11-18 12:07:37 +00:00
|
|
|
{t('docs.ctaSubtitle')}
|
2025-10-17 18:14:28 +02:00
|
|
|
</p>
|
|
|
|
|
<Link
|
|
|
|
|
to="/register"
|
|
|
|
|
className="inline-flex items-center gap-2 px-8 py-4 bg-white text-[var(--color-primary)] rounded-xl font-bold hover:shadow-2xl transition-all hover:scale-105"
|
|
|
|
|
>
|
2025-11-18 12:07:37 +00:00
|
|
|
<span>{t('docs.ctaButton')}</span>
|
2025-10-17 18:14:28 +02:00
|
|
|
<ChevronRight className="w-5 h-5" />
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
</PublicLayout>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default DocumentationPage;
|