Improve the frontend 3

This commit is contained in:
Urtzi Alfaro
2025-10-30 21:08:07 +01:00
parent 36217a2729
commit 63f5c6d512
184 changed files with 21512 additions and 7442 deletions

View File

@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { Store, MapPin, Clock, Phone, Mail, Globe, Save, X, Edit3, Zap, Plus, Settings, Trash2, Wifi, WifiOff, AlertCircle, CheckCircle, Loader, Eye, EyeOff, Info } from 'lucide-react';
import { Button, Card, Input, Select, Modal, Badge, Tabs } from '../../../../components/ui';
import { PageHeader } from '../../../../components/layout';
import { useToast } from '../../../../hooks/ui/useToast';
import { showToast } from '../../../../utils/toast';
import { usePOSConfigurationData, usePOSConfigurationManager } from '../../../../api/hooks/pos';
import { POSConfiguration, POSProviderConfig } from '../../../../api/types/pos';
import { posService } from '../../../../api/services/pos';
@@ -38,7 +38,7 @@ interface BusinessHours {
const BakeryConfigPage: React.FC = () => {
const { addToast } = useToast();
const currentTenant = useCurrentTenant();
const { loadUserTenants, setCurrentTenant } = useTenantActions();
const tenantId = currentTenant?.id || '';
@@ -287,9 +287,9 @@ const BakeryConfigPage: React.FC = () => {
}
setHasUnsavedChanges(false);
addToast('Configuración actualizada correctamente', { type: 'success' });
showToast.success('Configuración actualizada correctamente');
} catch (error) {
addToast(`Error al actualizar: ${error instanceof Error ? error.message : 'Error desconocido'}`, { type: 'error' });
showToast.error(`Error al actualizar: ${error instanceof Error ? error.message : 'Error desconocido'}`);
} finally {
setIsLoading(false);
}
@@ -364,7 +364,7 @@ const BakeryConfigPage: React.FC = () => {
.map(field => field.label);
if (missingFields.length > 0) {
addToast(`Campos requeridos: ${missingFields.join(', ')}`, 'error');
showToast.error(`Campos requeridos: ${missingFields.join(', ')}`);
return;
}
@@ -375,7 +375,7 @@ const BakeryConfigPage: React.FC = () => {
config_id: selectedPosConfig.id,
...posFormData,
});
addToast('Configuración actualizada correctamente', 'success');
showToast.success('Configuración actualizada correctamente');
setShowEditPosModal(false);
loadPosConfigurations();
} else {
@@ -384,12 +384,12 @@ const BakeryConfigPage: React.FC = () => {
tenant_id: tenantId,
...posFormData,
});
addToast('Configuración creada correctamente', 'success');
showToast.success('Configuración creada correctamente');
setShowAddPosModal(false);
loadPosConfigurations();
}
} catch (error) {
addToast('Error al guardar la configuración', 'error');
showToast.error('Error al guardar la configuración');
}
};
@@ -402,12 +402,12 @@ const BakeryConfigPage: React.FC = () => {
});
if (response.success) {
addToast('Conexión exitosa', 'success');
showToast.success('Conexión exitosa');
} else {
addToast(`Error en la conexión: ${response.message || 'Error desconocido'}`, 'error');
showToast.error(`Error en la conexión: ${response.message || 'Error desconocido'}`);
}
} catch (error) {
addToast('Error al probar la conexión', 'error');
showToast.error('Error al probar la conexión');
} finally {
setTestingConnection(null);
}
@@ -423,10 +423,10 @@ const BakeryConfigPage: React.FC = () => {
tenant_id: tenantId,
config_id: configId,
});
addToast('Configuración eliminada correctamente', 'success');
showToast.success('Configuración eliminada correctamente');
loadPosConfigurations();
} catch (error) {
addToast('Error al eliminar la configuración', 'error');
showToast.error('Error al eliminar la configuración');
}
};
@@ -1116,4 +1116,4 @@ const BakeryConfigPage: React.FC = () => {
);
};
export default BakeryConfigPage;
export default BakeryConfigPage;

View File

@@ -4,7 +4,7 @@ import { Store, MapPin, Clock, Settings as SettingsIcon, Save, X, AlertCircle, L
import { Button, Card, Input, Select } from '../../../../components/ui';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../../../../components/ui/Tabs';
import { PageHeader } from '../../../../components/layout';
import { useToast } from '../../../../hooks/ui/useToast';
import { showToast } from '../../../../utils/toast';
import { useUpdateTenant } from '../../../../api/hooks/tenant';
import { useCurrentTenant, useTenantActions } from '../../../../stores/tenant.store';
import { useSettings, useUpdateSettings } from '../../../../api/hooks/settings';
@@ -49,7 +49,7 @@ interface BusinessHours {
const BakerySettingsPage: React.FC = () => {
const { t } = useTranslation('settings');
const { addToast } = useToast();
const currentTenant = useCurrentTenant();
const { loadUserTenants, setCurrentTenant } = useTenantActions();
const tenantId = currentTenant?.id || '';
@@ -221,10 +221,10 @@ const BakerySettingsPage: React.FC = () => {
}
setHasUnsavedChanges(false);
addToast(t('bakery.save_success'), { type: 'success' });
showToast.success(t('bakery.save_success'));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : t('common.error');
addToast(`${t('bakery.save_error')}: ${errorMessage}`, { type: 'error' });
showToast.error(`${t('bakery.save_error')}: ${errorMessage}`);
} finally {
setIsLoading(false);
}
@@ -252,10 +252,10 @@ const BakerySettingsPage: React.FC = () => {
});
setHasUnsavedChanges(false);
addToast(t('bakery.save_success'), { type: 'success' });
showToast.success(t('bakery.save_success'));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : t('common.error');
addToast(`${t('bakery.save_error')}: ${errorMessage}`, { type: 'error' });
showToast.error(`${t('bakery.save_error')}: ${errorMessage}`);
} finally {
setIsLoading(false);
}

View File

@@ -23,7 +23,7 @@ import {
Sun,
Settings
} from 'lucide-react';
import { useToast } from '../../../../hooks/ui/useToast';
import { showToast } from '../../../../utils/toast';
// Backend-aligned preference types
export interface NotificationPreferences {
@@ -75,7 +75,7 @@ const CommunicationPreferences: React.FC<CommunicationPreferencesProps> = ({
onReset,
hasChanges
}) => {
const { addToast } = useToast();
const [isLoading, setIsLoading] = useState(false);
const [preferences, setPreferences] = useState<NotificationPreferences>({
@@ -161,9 +161,9 @@ const CommunicationPreferences: React.FC<CommunicationPreferencesProps> = ({
try {
setIsLoading(true);
await onSave(preferences);
addToast('Preferencias guardadas correctamente', 'success');
showToast.success('Preferencias guardadas correctamente');
} catch (error) {
addToast('Error al guardar las preferencias', 'error');
showToast.error('Error al guardar las preferencias');
} finally {
setIsLoading(false);
}
@@ -700,4 +700,4 @@ const CommunicationPreferences: React.FC<CommunicationPreferencesProps> = ({
);
};
export default CommunicationPreferences;
export default CommunicationPreferences;

View File

@@ -22,7 +22,7 @@ import {
import { Button, Card, Avatar, Input, Select } from '../../../../components/ui';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../../../../components/ui/Tabs';
import { PageHeader } from '../../../../components/layout';
import { useToast } from '../../../../hooks/ui/useToast';
import { showToast } from '../../../../utils/toast';
import { useAuthUser, useAuthActions } from '../../../../stores/auth.store';
import { useAuthProfile, useUpdateProfile, useChangePassword } from '../../../../api/hooks/auth';
import { useCurrentTenant } from '../../../../stores';
@@ -49,7 +49,7 @@ interface PasswordData {
const NewProfileSettingsPage: React.FC = () => {
const { t } = useTranslation('settings');
const navigate = useNavigate();
const { addToast } = useToast();
const user = useAuthUser();
const { logout } = useAuthActions();
const currentTenant = useCurrentTenant();
@@ -169,9 +169,9 @@ const NewProfileSettingsPage: React.FC = () => {
await updateProfileMutation.mutateAsync(profileData);
setIsEditing(false);
addToast(t('profile.save_changes'), { type: 'success' });
showToast.success(t('profile.save_changes'));
} catch (error) {
addToast(t('common.error'), { type: 'error' });
showToast.error(t('common.error'));
} finally {
setIsLoading(false);
}
@@ -191,9 +191,9 @@ const NewProfileSettingsPage: React.FC = () => {
setShowPasswordForm(false);
setPasswordData({ currentPassword: '', newPassword: '', confirmPassword: '' });
addToast(t('profile.password.change_success'), { type: 'success' });
showToast.success(t('profile.password.change_success'));
} catch (error) {
addToast(t('profile.password.change_error'), { type: 'error' });
showToast.error(t('profile.password.change_error'));
} finally {
setIsLoading(false);
}
@@ -246,9 +246,9 @@ const NewProfileSettingsPage: React.FC = () => {
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
addToast(t('profile.privacy.export_success'), { type: 'success' });
showToast.success(t('profile.privacy.export_success'));
} catch (err) {
addToast(t('profile.privacy.export_error'), { type: 'error' });
showToast.error(t('profile.privacy.export_error'));
} finally {
setIsExporting(false);
}
@@ -256,12 +256,12 @@ const NewProfileSettingsPage: React.FC = () => {
const handleAccountDeletion = async () => {
if (deleteConfirmEmail.toLowerCase() !== user?.email?.toLowerCase()) {
addToast(t('common.error'), { type: 'error' });
showToast.error(t('common.error'));
return;
}
if (!deletePassword) {
addToast(t('common.error'), { type: 'error' });
showToast.error(t('common.error'));
return;
}
@@ -270,14 +270,14 @@ const NewProfileSettingsPage: React.FC = () => {
const { authService } = await import('../../../../api');
await authService.deleteAccount(deleteConfirmEmail, deletePassword, deleteReason);
addToast(t('common.success'), { type: 'success' });
showToast.success(t('common.success'));
setTimeout(() => {
logout();
navigate('/');
}, 2000);
} catch (err: any) {
addToast(err.message || t('common.error'), { type: 'error' });
showToast.error(err.message || t('common.error'));
} finally {
setIsDeleting(false);
}

View File

@@ -4,7 +4,7 @@ import { Button, Card, Avatar, Input, Select, Tabs, Badge, Modal } from '../../.
import { PageHeader } from '../../../../components/layout';
import { useAuthUser } from '../../../../stores/auth.store';
import { useCurrentTenant } from '../../../../stores';
import { useToast } from '../../../../hooks/ui/useToast';
import { showToast } from '../../../../utils/toast';
import { useAuthProfile, useUpdateProfile, useChangePassword } from '../../../../api/hooks/auth';
import { subscriptionService, type UsageSummary, type AvailablePlans } from '../../../../api';
import { useTranslation } from 'react-i18next';
@@ -30,7 +30,7 @@ interface PasswordData {
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();
@@ -176,9 +176,9 @@ const ProfilePage: React.FC = () => {
await updateProfileMutation.mutateAsync(profileData);
setIsEditing(false);
addToast('Perfil actualizado correctamente', 'success');
showToast.success('Perfil actualizado correctamente');
} catch (error) {
addToast('No se pudo actualizar tu perfil', 'error');
showToast.error('No se pudo actualizar tu perfil');
} finally {
setIsLoading(false);
}
@@ -198,9 +198,9 @@ const ProfilePage: React.FC = () => {
setShowPasswordForm(false);
setPasswordData({ currentPassword: '', newPassword: '', confirmPassword: '' });
addToast('Contraseña actualizada correctamente', 'success');
showToast.success('Contraseña actualizada correctamente');
} catch (error) {
addToast('No se pudo cambiar tu contraseña', 'error');
showToast.error('No se pudo cambiar tu contraseña');
} finally {
setIsLoading(false);
}
@@ -269,7 +269,7 @@ const ProfilePage: React.FC = () => {
const tenantId = currentTenant?.id || user?.tenant_id;
if (!tenantId) {
addToast('No se encontró información del tenant', 'error');
showToast.error('No se encontró información del tenant');
return;
}
@@ -284,7 +284,7 @@ const ProfilePage: React.FC = () => {
setAvailablePlans(plans);
} catch (error) {
console.error('Error loading subscription data:', error);
addToast("No se pudo cargar la información de suscripción", 'error');
showToast.error("No se pudo cargar la información de suscripción");
} finally {
setSubscriptionLoading(false);
}
@@ -299,7 +299,7 @@ const ProfilePage: React.FC = () => {
const tenantId = currentTenant?.id || user?.tenant_id;
if (!tenantId || !selectedPlan) {
addToast('Información de tenant no disponible', 'error');
showToast.error('Información de tenant no disponible');
return;
}
@@ -312,24 +312,24 @@ const ProfilePage: React.FC = () => {
);
if (!validation.can_upgrade) {
addToast(validation.reason || 'No se puede actualizar el plan', 'error');
return;
showToast.error(validation.reason || 'No se puede actualizar el plan');
return;
}
const result = await subscriptionService.upgradePlan(tenantId, selectedPlan);
if (result.success) {
addToast(result.message, 'success');
showToast.success(result.message);
await loadSubscriptionData();
setUpgradeDialogOpen(false);
setSelectedPlan('');
} else {
addToast('Error al cambiar el plan', 'error');
showToast.error('Error al cambiar el plan');
}
} catch (error) {
console.error('Error upgrading plan:', error);
addToast('Error al procesar el cambio de plan', 'error');
showToast.error('Error al procesar el cambio de plan');
} finally {
setUpgrading(false);
}
@@ -953,4 +953,4 @@ const ProfilePage: React.FC = () => {
);
};
export default ProfilePage;
export default ProfilePage;

View File

@@ -5,7 +5,7 @@ import { DialogModal } from '../../../../components/ui/DialogModal/DialogModal';
import { PageHeader } from '../../../../components/layout';
import { useAuthUser } from '../../../../stores/auth.store';
import { useCurrentTenant } from '../../../../stores';
import { useToast } from '../../../../hooks/ui/useToast';
import { showToast } from '../../../../utils/toast';
import { subscriptionService, type UsageSummary, type AvailablePlans } from '../../../../api';
import { useSubscriptionEvents } from '../../../../contexts/SubscriptionEventsContext';
import { SubscriptionPricingCards } from '../../../../components/subscription/SubscriptionPricingCards';
@@ -13,7 +13,6 @@ import { SubscriptionPricingCards } from '../../../../components/subscription/Su
const SubscriptionPage: React.FC = () => {
const user = useAuthUser();
const currentTenant = useCurrentTenant();
const { addToast } = useToast();
const { notifySubscriptionChanged } = useSubscriptionEvents();
const [usageSummary, setUsageSummary] = useState<UsageSummary | null>(null);
@@ -36,7 +35,7 @@ const SubscriptionPage: React.FC = () => {
const tenantId = currentTenant?.id || user?.tenant_id;
if (!tenantId) {
addToast('No se encontró información del tenant', { type: 'error' });
showToast.error('No se encontró información del tenant');
return;
}
@@ -120,7 +119,7 @@ const SubscriptionPage: React.FC = () => {
setAvailablePlans(plans);
} catch (error) {
console.error('Error loading subscription data:', error);
addToast("No se pudo cargar la información de suscripción", { type: 'error' });
showToast.error("No se pudo cargar la información de suscripción");
} finally {
setSubscriptionLoading(false);
}
@@ -135,7 +134,7 @@ const SubscriptionPage: React.FC = () => {
const tenantId = currentTenant?.id || user?.tenant_id;
if (!tenantId || !selectedPlan) {
addToast('Información de tenant no disponible', { type: 'error' });
showToast.error('Información de tenant no disponible');
return;
}
@@ -148,14 +147,17 @@ const SubscriptionPage: React.FC = () => {
);
if (!validation.can_upgrade) {
addToast(validation.reason || 'No se puede actualizar el plan', { type: 'error' });
showToast.error(validation.reason || 'No se puede actualizar el plan');
return;
}
const result = await subscriptionService.upgradePlan(tenantId, selectedPlan);
if (result.success) {
addToast(result.message, { type: 'success' });
showToast.success(result.message);
// Invalidate cache to ensure fresh data on next fetch
subscriptionService.invalidateCache();
// Broadcast subscription change event to refresh sidebar and other components
notifySubscriptionChanged();
@@ -164,11 +166,11 @@ const SubscriptionPage: React.FC = () => {
setUpgradeDialogOpen(false);
setSelectedPlan('');
} else {
addToast('Error al cambiar el plan', { type: 'error' });
showToast.error('Error al cambiar el plan');
}
} catch (error) {
console.error('Error upgrading plan:', error);
addToast('Error al procesar el cambio de plan', { type: 'error' });
showToast.error('Error al procesar el cambio de plan');
} finally {
setUpgrading(false);
}
@@ -182,7 +184,7 @@ const SubscriptionPage: React.FC = () => {
const tenantId = currentTenant?.id || user?.tenant_id;
if (!tenantId) {
addToast('Información de tenant no disponible', { type: 'error' });
showToast.error('Información de tenant no disponible');
return;
}
@@ -199,9 +201,8 @@ const SubscriptionPage: React.FC = () => {
day: 'numeric'
});
addToast(
`Suscripción cancelada. Acceso de solo lectura a partir del ${effectiveDate} (${daysRemaining} días restantes)`,
{ type: 'success' }
showToast.success(
`Suscripción cancelada. Acceso de solo lectura a partir del ${effectiveDate} (${daysRemaining} días restantes)`
);
}
@@ -209,7 +210,7 @@ const SubscriptionPage: React.FC = () => {
setCancellationDialogOpen(false);
} catch (error) {
console.error('Error cancelling subscription:', error);
addToast('Error al cancelar la suscripción', { type: 'error' });
showToast.error('Error al cancelar la suscripción');
} finally {
setCancelling(false);
}
@@ -219,7 +220,7 @@ const SubscriptionPage: React.FC = () => {
const tenantId = currentTenant?.id || user?.tenant_id;
if (!tenantId) {
addToast('No se encontró información del tenant', { type: 'error' });
showToast.error('No se encontró información del tenant');
return;
}
@@ -236,7 +237,7 @@ const SubscriptionPage: React.FC = () => {
]);
} catch (error) {
console.error('Error loading invoices:', error);
addToast('Error al cargar las facturas', { type: 'error' });
showToast.error('Error al cargar las facturas');
} finally {
setInvoicesLoading(false);
}
@@ -245,7 +246,7 @@ const SubscriptionPage: React.FC = () => {
const handleDownloadInvoice = (invoiceId: string) => {
// In a real implementation, this would download the actual invoice
console.log(`Downloading invoice: ${invoiceId}`);
addToast(`Descargando factura ${invoiceId}`, { type: 'info' });
showToast.info(`Descargando factura ${invoiceId}`);
};
const ProgressBar: React.FC<{ value: number; className?: string }> = ({ value, className = '' }) => {
@@ -389,7 +390,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.users.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.users.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.users.unlimited ? 'Ilimitado' : `${usageSummary.usage.users.limit - usageSummary.usage.users.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.users.unlimited ? 'Ilimitado' : `${(usageSummary.usage.users.limit ?? 0) - usageSummary.usage.users.current} restantes`}</span>
</p>
</div>
@@ -410,7 +411,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.locations.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.locations.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.locations.unlimited ? 'Ilimitado' : `${usageSummary.usage.locations.limit - usageSummary.usage.locations.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.locations.unlimited ? 'Ilimitado' : `${(usageSummary.usage.locations.limit ?? 0) - usageSummary.usage.locations.current} restantes`}</span>
</p>
</div>
</div>
@@ -437,7 +438,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.products.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.products.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.products.unlimited ? 'Ilimitado' : `${usageSummary.usage.products.limit - usageSummary.usage.products.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.products.unlimited ? 'Ilimitado' : `${(usageSummary.usage.products.limit ?? 0) - usageSummary.usage.products.current} restantes`}</span>
</p>
</div>
@@ -458,7 +459,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.recipes.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.recipes.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.recipes.unlimited ? 'Ilimitado' : `${usageSummary.usage.recipes.limit - usageSummary.usage.recipes.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.recipes.unlimited ? 'Ilimitado' : `${(usageSummary.usage.recipes.limit ?? 0) - usageSummary.usage.recipes.current} restantes`}</span>
</p>
</div>
@@ -479,7 +480,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.suppliers.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.suppliers.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.suppliers.unlimited ? 'Ilimitado' : `${usageSummary.usage.suppliers.limit - usageSummary.usage.suppliers.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.suppliers.unlimited ? 'Ilimitado' : `${(usageSummary.usage.suppliers.limit ?? 0) - usageSummary.usage.suppliers.current} restantes`}</span>
</p>
</div>
</div>
@@ -506,7 +507,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.training_jobs_today.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.training_jobs_today.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.training_jobs_today.unlimited ? 'Ilimitado' : `${usageSummary.usage.training_jobs_today.limit - usageSummary.usage.training_jobs_today.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.training_jobs_today.unlimited ? 'Ilimitado' : `${(usageSummary.usage.training_jobs_today.limit ?? 0) - usageSummary.usage.training_jobs_today.current} restantes`}</span>
</p>
</div>
@@ -527,7 +528,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.forecasts_today.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.forecasts_today.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.forecasts_today.unlimited ? 'Ilimitado' : `${usageSummary.usage.forecasts_today.limit - usageSummary.usage.forecasts_today.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.forecasts_today.unlimited ? 'Ilimitado' : `${(usageSummary.usage.forecasts_today.limit ?? 0) - usageSummary.usage.forecasts_today.current} restantes`}</span>
</p>
</div>
</div>
@@ -554,7 +555,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.api_calls_this_hour.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.api_calls_this_hour.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.api_calls_this_hour.unlimited ? 'Ilimitado' : `${usageSummary.usage.api_calls_this_hour.limit - usageSummary.usage.api_calls_this_hour.current} restantes`}</span>
<span className="font-medium">{usageSummary.usage.api_calls_this_hour.unlimited ? 'Ilimitado' : `${(usageSummary.usage.api_calls_this_hour.limit ?? 0) - usageSummary.usage.api_calls_this_hour.current} restantes`}</span>
</p>
</div>
@@ -575,7 +576,7 @@ const SubscriptionPage: React.FC = () => {
<ProgressBar value={usageSummary.usage.file_storage_used_gb.usage_percentage} />
<p className="text-xs text-[var(--text-secondary)] flex items-center justify-between">
<span>{usageSummary.usage.file_storage_used_gb.usage_percentage}% utilizado</span>
<span className="font-medium">{usageSummary.usage.file_storage_used_gb.unlimited ? 'Ilimitado' : `${(usageSummary.usage.file_storage_used_gb.limit - usageSummary.usage.file_storage_used_gb.current).toFixed(2)} GB restantes`}</span>
<span className="font-medium">{usageSummary.usage.file_storage_used_gb.unlimited ? 'Ilimitado' : `${((usageSummary.usage.file_storage_used_gb.limit ?? 0) - usageSummary.usage.file_storage_used_gb.current).toFixed(2)} GB restantes`}</span>
</p>
</div>
</div>

View File

@@ -9,13 +9,13 @@ import { useUserActivity } from '../../../../api/hooks/user';
import { userService } from '../../../../api/services/user';
import { useAuthUser } from '../../../../stores/auth.store';
import { useCurrentTenant, useCurrentTenantAccess } from '../../../../stores/tenant.store';
import { useToast } from '../../../../hooks/ui/useToast';
import { showToast } from '../../../../utils/toast';
import { TENANT_ROLES, type TenantRole } from '../../../../types/roles';
import { subscriptionService } from '../../../../api/services/subscription';
const TeamPage: React.FC = () => {
const { t } = useTranslation(['settings']);
const { addToast } = useToast();
const currentUser = useAuthUser();
const currentTenant = useCurrentTenant();
const currentTenantAccess = useCurrentTenantAccess();
@@ -310,7 +310,7 @@ const TeamPage: React.FC = () => {
setShowActivityModal(true);
} catch (error) {
console.error('Error fetching user activity:', error);
addToast('Error al cargar la actividad del usuario', { type: 'error' });
showToast.error('Error al cargar la actividad del usuario');
} finally {
setActivityLoading(false);
}
@@ -359,9 +359,9 @@ const TeamPage: React.FC = () => {
memberUserId,
});
addToast('Miembro removido exitosamente', { type: 'success' });
showToast.success('Miembro removido exitosamente');
} catch (error) {
addToast('Error al remover miembro', { type: 'error' });
showToast.error('Error al remover miembro');
}
};
@@ -375,9 +375,9 @@ const TeamPage: React.FC = () => {
newRole,
});
addToast('Rol actualizado exitosamente', { type: 'success' });
showToast.success('Rol actualizado exitosamente');
} catch (error) {
addToast('Error al actualizar rol', { type: 'error' });
showToast.error('Error al actualizar rol');
}
};
@@ -556,7 +556,7 @@ const TeamPage: React.FC = () => {
if (!usageCheck.allowed) {
const errorMessage = usageCheck.message ||
`Has alcanzado el límite de ${usageCheck.limit} usuarios para tu plan. Actualiza tu suscripción para agregar más miembros.`;
addToast(errorMessage, { type: 'error' });
showToast.error(errorMessage);
throw new Error(errorMessage);
}
@@ -579,14 +579,14 @@ const TeamPage: React.FC = () => {
timezone: 'Europe/Madrid'
}
});
addToast('Usuario creado y agregado exitosamente', { type: 'success' });
showToast.success('Usuario creado y agregado exitosamente');
} else {
await addMemberMutation.mutateAsync({
tenantId,
userId: userData.userId!,
role,
});
addToast('Miembro agregado exitosamente', { type: 'success' });
showToast.success('Miembro agregado exitosamente');
}
setShowAddForm(false);
@@ -597,9 +597,8 @@ const TeamPage: React.FC = () => {
// Limit error already toasted above
throw error;
}
addToast(
userData.createUser ? 'Error al crear usuario' : 'Error al agregar miembro',
{ type: 'error' }
showToast.error(
userData.createUser ? 'Error al crear usuario' : 'Error al agregar miembro'
);
throw error;
}