import React, { useState } from 'react'; import { User, Mail, Phone, Lock, Globe, Clock, Camera, Save, X, Bell, MessageSquare, Smartphone, RotateCcw, CreditCard, Crown, Package, MapPin, Users, TrendingUp, Calendar, CheckCircle, AlertCircle, ArrowRight, Star, RefreshCw, Settings, Download, ExternalLink } from 'lucide-react'; import { Button, Card, Avatar, Input, Select, Tabs, Badge, Modal } from '../../../../components/ui'; import { PageHeader } from '../../../../components/layout'; import { useAuthUser } from '../../../../stores/auth.store'; import { useCurrentTenant } from '../../../../stores'; import { useToast } from '../../../../hooks/ui/useToast'; import { useAuthProfile, useUpdateProfile, useChangePassword } from '../../../../api/hooks/auth'; import { subscriptionService, type UsageSummary, type AvailablePlans } from '../../../../api'; import { useTranslation } from 'react-i18next'; import CommunicationPreferences, { type NotificationPreferences } from './CommunicationPreferences'; interface ProfileFormData { first_name: string; last_name: string; email: string; phone: string; language: string; timezone: string; avatar?: string; } interface PasswordData { currentPassword: string; newPassword: string; confirmPassword: string; } const ProfilePage: React.FC = () => { const user = useAuthUser(); const { t } = useTranslation(['settings', 'auth']); const { addToast } = useToast(); const { data: profile, isLoading: profileLoading, error: profileError } = useAuthProfile(); const updateProfileMutation = useUpdateProfile(); const changePasswordMutation = useChangePassword(); const [isEditing, setIsEditing] = useState(false); const [isLoading, setIsLoading] = useState(false); const [showPasswordForm, setShowPasswordForm] = useState(false); const [activeTab, setActiveTab] = useState('profile'); const [hasPreferencesChanges, setHasPreferencesChanges] = useState(false); const [usageSummary, setUsageSummary] = useState(null); const [availablePlans, setAvailablePlans] = useState(null); const [subscriptionLoading, setSubscriptionLoading] = useState(false); const [upgradeDialogOpen, setUpgradeDialogOpen] = useState(false); const [selectedPlan, setSelectedPlan] = useState(''); const [upgrading, setUpgrading] = useState(false); const currentTenant = useCurrentTenant(); const [profileData, setProfileData] = useState({ first_name: '', last_name: '', email: '', phone: '', language: 'es', timezone: 'Europe/Madrid' }); // Update profile data when profile is loaded React.useEffect(() => { if (profile) { setProfileData({ first_name: profile.first_name || '', last_name: profile.last_name || '', email: profile.email || '', phone: profile.phone || '', language: profile.language || 'es', timezone: profile.timezone || 'Europe/Madrid', avatar: profile.avatar || '' }); // Update notification preferences with profile data setNotificationPreferences(prev => ({ ...prev, language: profile.language || 'es', timezone: profile.timezone || 'Europe/Madrid' })); } }, [profile]); // Load subscription data when needed React.useEffect(() => { if (activeTab === 'subscription' && (currentTenant?.id || user?.tenant_id) && !usageSummary) { loadSubscriptionData(); } }, [activeTab, currentTenant, user?.tenant_id]); const [passwordData, setPasswordData] = useState({ currentPassword: '', newPassword: '', confirmPassword: '' }); const [errors, setErrors] = useState>({}); const [notificationPreferences, setNotificationPreferences] = useState({ email_enabled: true, email_alerts: true, email_marketing: false, email_reports: true, whatsapp_enabled: false, whatsapp_alerts: false, whatsapp_reports: false, push_enabled: true, push_alerts: true, push_reports: false, quiet_hours_start: '22:00', quiet_hours_end: '08:00', timezone: 'Europe/Madrid', digest_frequency: 'daily', max_emails_per_day: 10, language: 'es' }); const languageOptions = [ { value: 'es', label: 'Español' }, { value: 'ca', label: 'Català' }, { value: 'en', label: 'English' } ]; const timezoneOptions = [ { value: 'Europe/Madrid', label: 'Madrid (CET/CEST)' }, { value: 'Atlantic/Canary', label: 'Canarias (WET/WEST)' }, { value: 'Europe/London', label: 'Londres (GMT/BST)' } ]; const validateProfile = (): boolean => { const newErrors: Record = {}; if (!profileData.first_name.trim()) { newErrors.first_name = 'El nombre es requerido'; } if (!profileData.last_name.trim()) { newErrors.last_name = 'Los apellidos son requeridos'; } if (!profileData.email.trim()) { newErrors.email = 'El email es requerido'; } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(profileData.email)) { newErrors.email = 'Email inválido'; } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const validatePassword = (): boolean => { const newErrors: Record = {}; if (!passwordData.currentPassword) { newErrors.currentPassword = 'Contraseña actual requerida'; } if (!passwordData.newPassword) { newErrors.newPassword = 'Nueva contraseña requerida'; } else if (passwordData.newPassword.length < 8) { newErrors.newPassword = 'Mínimo 8 caracteres'; } if (passwordData.newPassword !== passwordData.confirmPassword) { newErrors.confirmPassword = 'Las contraseñas no coinciden'; } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSaveProfile = async () => { if (!validateProfile()) return; setIsLoading(true); try { await updateProfileMutation.mutateAsync(profileData); setIsEditing(false); addToast('Perfil actualizado correctamente', 'success'); } catch (error) { addToast('No se pudo actualizar tu perfil', 'error'); } finally { setIsLoading(false); } }; const handleChangePasswordSubmit = async () => { if (!validatePassword()) return; setIsLoading(true); try { await changePasswordMutation.mutateAsync({ current_password: passwordData.currentPassword, new_password: passwordData.newPassword, confirm_password: passwordData.confirmPassword }); setShowPasswordForm(false); setPasswordData({ currentPassword: '', newPassword: '', confirmPassword: '' }); addToast('Contraseña actualizada correctamente', 'success'); } catch (error) { addToast('No se pudo cambiar tu contraseña', 'error'); } finally { setIsLoading(false); } }; const handleInputChange = (field: keyof ProfileFormData) => (e: React.ChangeEvent) => { setProfileData(prev => ({ ...prev, [field]: e.target.value })); if (errors[field]) { setErrors(prev => ({ ...prev, [field]: '' })); } }; const handleSelectChange = (field: keyof ProfileFormData) => (value: string) => { setProfileData(prev => ({ ...prev, [field]: value })); }; const handlePasswordChange = (field: keyof PasswordData) => (e: React.ChangeEvent) => { setPasswordData(prev => ({ ...prev, [field]: e.target.value })); if (errors[field]) { setErrors(prev => ({ ...prev, [field]: '' })); } }; // Notification preferences handlers const handleSaveNotificationPreferences = async (preferences: NotificationPreferences) => { try { await updateProfileMutation.mutateAsync({ language: preferences.language, timezone: preferences.timezone, notification_preferences: preferences }); setNotificationPreferences(preferences); setHasPreferencesChanges(false); } catch (error) { throw error; // Let the component handle the error display } }; const handleResetNotificationPreferences = () => { if (profile) { setNotificationPreferences({ email_enabled: true, email_alerts: true, email_marketing: false, email_reports: true, whatsapp_enabled: false, whatsapp_alerts: false, whatsapp_reports: false, push_enabled: true, push_alerts: true, push_reports: false, quiet_hours_start: '22:00', quiet_hours_end: '08:00', timezone: profile.timezone || 'Europe/Madrid', digest_frequency: 'daily', max_emails_per_day: 10, language: profile.language || 'es' }); setHasPreferencesChanges(false); } }; // Subscription handlers const loadSubscriptionData = async () => { const tenantId = currentTenant?.id || user?.tenant_id; if (!tenantId) { addToast('No se encontró información del tenant', 'error'); return; } try { setSubscriptionLoading(true); const [usage, plans] = await Promise.all([ subscriptionService.getUsageSummary(tenantId), subscriptionService.getAvailablePlans() ]); setUsageSummary(usage); setAvailablePlans(plans); } catch (error) { console.error('Error loading subscription data:', error); addToast("No se pudo cargar la información de suscripción", 'error'); } finally { setSubscriptionLoading(false); } }; const handleUpgradeClick = (planKey: string) => { setSelectedPlan(planKey); setUpgradeDialogOpen(true); }; const handleUpgradeConfirm = async () => { const tenantId = currentTenant?.id || user?.tenant_id; if (!tenantId || !selectedPlan) { addToast('Información de tenant no disponible', 'error'); return; } try { setUpgrading(true); const validation = await subscriptionService.validatePlanUpgrade( tenantId, selectedPlan ); if (!validation.can_upgrade) { addToast(validation.reason || 'No se puede actualizar el plan', 'error'); return; } const result = await subscriptionService.upgradePlan(tenantId, selectedPlan); if (result.success) { addToast(result.message, 'success'); await loadSubscriptionData(); setUpgradeDialogOpen(false); setSelectedPlan(''); } else { addToast('Error al cambiar el plan', 'error'); } } catch (error) { console.error('Error upgrading plan:', error); addToast('Error al procesar el cambio de plan', 'error'); } finally { setUpgrading(false); } }; const ProgressBar: React.FC<{ value: number; className?: string }> = ({ value, className = '' }) => { const getProgressColor = () => { if (value >= 90) return 'bg-red-500'; if (value >= 80) return 'bg-yellow-500'; return 'bg-green-500'; }; return (
); }; const tabItems = [ { id: 'profile', label: 'Información Personal' }, { id: 'preferences', label: 'Preferencias de Comunicación' }, { id: 'subscription', label: 'Suscripción y Facturación' } ]; return (
{/* Tab Navigation */} {/* Profile Header */} {activeTab === 'profile' && (

{profileData.first_name} {profileData.last_name}

{profileData.email}

{user?.role && (

{t(`global_roles.${user.role}`)}

)}
{t('settings:profile.online', 'En línea')}
{!isEditing && ( )}
)} {/* Profile Form */} {activeTab === 'profile' && (

{t('settings:profile.personal_info', 'Información Personal')}

} /> } /> } /> } />
{isEditing && (
)}
)} {/* Password Change Form */} {activeTab === 'profile' && showPasswordForm && (

Cambiar Contraseña

} /> } /> } />
)} {/* Communication Preferences Tab */} {activeTab === 'preferences' && ( )} {/* Subscription Tab */} {activeTab === 'subscription' && ( <> {subscriptionLoading ? (

Cargando información de suscripción...

) : !usageSummary || !availablePlans ? (

No se pudo cargar la información

Hubo un problema al cargar los datos de suscripción

) : ( <> {/* Current Plan Overview */}

Plan Actual: {subscriptionService.getPlanDisplayInfo(usageSummary.plan).name}

{usageSummary.status === 'active' ? 'Activo' : usageSummary.status}
Precio Mensual {subscriptionService.formatPrice(usageSummary.monthly_price)}
Próxima Facturación {new Date(usageSummary.next_billing_date).toLocaleDateString('es-ES', { day: '2-digit', month: '2-digit' })}
Usuarios {usageSummary.usage.users.current}/{usageSummary.usage.users.unlimited ? '∞' : usageSummary.usage.users.limit}
Ubicaciones {usageSummary.usage.locations.current}/{usageSummary.usage.locations.unlimited ? '∞' : usageSummary.usage.locations.limit}
{/* Usage Details */}

Uso de Recursos

{/* Users */}
Usuarios
{usageSummary.usage.users.current}/ {usageSummary.usage.users.unlimited ? '∞' : usageSummary.usage.users.limit}

{usageSummary.usage.users.usage_percentage}% utilizado {usageSummary.usage.users.unlimited ? 'Ilimitado' : `${usageSummary.usage.users.limit - usageSummary.usage.users.current} restantes`}

{/* Locations */}
Ubicaciones
{usageSummary.usage.locations.current}/ {usageSummary.usage.locations.unlimited ? '∞' : usageSummary.usage.locations.limit}

{usageSummary.usage.locations.usage_percentage}% utilizado {usageSummary.usage.locations.unlimited ? 'Ilimitado' : `${usageSummary.usage.locations.limit - usageSummary.usage.locations.current} restantes`}

{/* Products */}
Productos
{usageSummary.usage.products.current}/ {usageSummary.usage.products.unlimited ? '∞' : usageSummary.usage.products.limit}

{usageSummary.usage.products.usage_percentage}% utilizado {usageSummary.usage.products.unlimited ? 'Ilimitado' : 'Ilimitado'}

{/* Available Plans */}

Planes Disponibles

{Object.entries(availablePlans.plans).map(([planKey, plan]) => { const isCurrentPlan = usageSummary.plan === planKey; const getPlanColor = () => { switch (planKey) { case 'starter': return 'border-blue-500/30 bg-blue-500/5'; case 'professional': return 'border-purple-500/30 bg-purple-500/5'; case 'enterprise': return 'border-amber-500/30 bg-amber-500/5'; default: return 'border-[var(--border-primary)] bg-[var(--bg-secondary)]'; } }; return ( {plan.popular && (
Más Popular
)}

{plan.name}

{subscriptionService.formatPrice(plan.monthly_price)} /mes

{plan.description}

{plan.max_users === -1 ? 'Usuarios ilimitados' : `${plan.max_users} usuarios`}
{plan.max_locations === -1 ? 'Ubicaciones ilimitadas' : `${plan.max_locations} ubicación${plan.max_locations > 1 ? 'es' : ''}`}
{plan.max_products === -1 ? 'Productos ilimitados' : `${plan.max_products} productos`}
{/* Features Section */}
Funcionalidades Incluidas
{(() => { const getPlanFeatures = (planKey: string) => { switch (planKey) { case 'starter': return [ '✓ Panel de Control Básico', '✓ Gestión de Inventario', '✓ Gestión de Pedidos', '✓ Gestión de Proveedores', '✓ Punto de Venta Básico', '✗ Analytics Avanzados', '✗ Pronósticos IA', '✗ Insights Predictivos' ]; case 'professional': return [ '✓ Panel de Control Avanzado', '✓ Gestión de Inventario Completa', '✓ Analytics de Ventas', '✓ Pronósticos con IA (92% precisión)', '✓ Análisis de Rendimiento', '✓ Optimización de Producción', '✓ Integración POS', '✗ Insights Predictivos Avanzados' ]; case 'enterprise': return [ '✓ Todas las funcionalidades Professional', '✓ Insights Predictivos con IA', '✓ Analytics Multi-ubicación', '✓ Integración ERP', '✓ API Personalizada', '✓ Gestor de Cuenta Dedicado', '✓ Soporte 24/7 Prioritario', '✓ Demo Personalizada' ]; default: return []; } }; return getPlanFeatures(planKey).map((feature, index) => (
{feature}
)); })()}
{isCurrentPlan ? ( Plan Actual ) : ( )}
); })}
)} )} {/* Upgrade Modal */} {upgradeDialogOpen && selectedPlan && availablePlans && ( setUpgradeDialogOpen(false)} title="Confirmar Cambio de Plan" >

¿Estás seguro de que quieres cambiar tu plan de suscripción?

{availablePlans.plans[selectedPlan] && usageSummary && (
Plan actual: {subscriptionService.getPlanDisplayInfo(usageSummary.plan).name}
Nuevo plan: {availablePlans.plans[selectedPlan].name}
Nuevo precio: {subscriptionService.formatPrice(availablePlans.plans[selectedPlan].monthly_price)}/mes
)}
)}
); }; export default ProfilePage;