Improve the frontend 2
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Crown, Users, MapPin, Package, TrendingUp, RefreshCw, AlertCircle, CheckCircle, ArrowRight, Star, ExternalLink, Download, CreditCard, X, Activity, Database, Zap, HardDrive, ShoppingCart, ChefHat } from 'lucide-react';
|
||||
import { Button, Card, Badge, Modal } from '../../../../components/ui';
|
||||
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 { subscriptionService, type UsageSummary, type AvailablePlans } from '../../../../api';
|
||||
import { useSubscriptionEvents } from '../../../../contexts/SubscriptionEventsContext';
|
||||
import { SubscriptionPricingCards } from '../../../../components/subscription/SubscriptionPricingCards';
|
||||
|
||||
const SubscriptionPage: React.FC = () => {
|
||||
const user = useAuthUser();
|
||||
const currentTenant = useCurrentTenant();
|
||||
const { addToast } = useToast();
|
||||
const { notifySubscriptionChanged } = useSubscriptionEvents();
|
||||
|
||||
const [usageSummary, setUsageSummary] = useState<UsageSummary | null>(null);
|
||||
const [availablePlans, setAvailablePlans] = useState<AvailablePlans | null>(null);
|
||||
@@ -154,6 +157,9 @@ const SubscriptionPage: React.FC = () => {
|
||||
if (result.success) {
|
||||
addToast(result.message, { type: 'success' });
|
||||
|
||||
// Broadcast subscription change event to refresh sidebar and other components
|
||||
notifySubscriptionChanged();
|
||||
|
||||
await loadSubscriptionData();
|
||||
setUpgradeDialogOpen(false);
|
||||
setSelectedPlan('');
|
||||
@@ -325,7 +331,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-[var(--text-secondary)]">Usuarios</span>
|
||||
<span className="font-medium text-[var(--text-primary)]">
|
||||
{usageSummary.usage.users.current}/{usageSummary.usage.users.unlimited ? '∞' : usageSummary.usage.users.limit}
|
||||
{usageSummary.usage.users.current}/{usageSummary.usage.users.unlimited ? '∞' : usageSummary.usage.users.limit ?? 0}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -333,7 +339,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-[var(--text-secondary)]">Ubicaciones</span>
|
||||
<span className="font-medium text-[var(--text-primary)]">
|
||||
{usageSummary.usage.locations.current}/{usageSummary.usage.locations.unlimited ? '∞' : usageSummary.usage.locations.limit}
|
||||
{usageSummary.usage.locations.current}/{usageSummary.usage.locations.unlimited ? '∞' : usageSummary.usage.locations.limit ?? 0}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -377,7 +383,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.users.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.users.unlimited ? '∞' : usageSummary.usage.users.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.users.unlimited ? '∞' : usageSummary.usage.users.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.users.usage_percentage} />
|
||||
@@ -398,7 +404,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.locations.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.locations.unlimited ? '∞' : usageSummary.usage.locations.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.locations.unlimited ? '∞' : usageSummary.usage.locations.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.locations.usage_percentage} />
|
||||
@@ -425,7 +431,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.products.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.products.unlimited ? '∞' : usageSummary.usage.products.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.products.unlimited ? '∞' : usageSummary.usage.products.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.products.usage_percentage} />
|
||||
@@ -446,7 +452,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.recipes.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.recipes.unlimited ? '∞' : usageSummary.usage.recipes.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.recipes.unlimited ? '∞' : usageSummary.usage.recipes.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.recipes.usage_percentage} />
|
||||
@@ -467,7 +473,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.suppliers.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.suppliers.unlimited ? '∞' : usageSummary.usage.suppliers.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.suppliers.unlimited ? '∞' : usageSummary.usage.suppliers.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.suppliers.usage_percentage} />
|
||||
@@ -494,7 +500,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.training_jobs_today.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.training_jobs_today.unlimited ? '∞' : usageSummary.usage.training_jobs_today.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.training_jobs_today.unlimited ? '∞' : usageSummary.usage.training_jobs_today.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.training_jobs_today.usage_percentage} />
|
||||
@@ -515,7 +521,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.forecasts_today.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.forecasts_today.unlimited ? '∞' : usageSummary.usage.forecasts_today.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.forecasts_today.unlimited ? '∞' : usageSummary.usage.forecasts_today.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.forecasts_today.usage_percentage} />
|
||||
@@ -542,7 +548,7 @@ const SubscriptionPage: React.FC = () => {
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[var(--text-primary)]">
|
||||
{usageSummary.usage.api_calls_this_hour.current}<span className="text-[var(--text-tertiary)]">/</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.api_calls_this_hour.unlimited ? '∞' : usageSummary.usage.api_calls_this_hour.limit}</span>
|
||||
<span className="text-[var(--text-tertiary)]">{usageSummary.usage.api_calls_this_hour.unlimited ? '∞' : usageSummary.usage.api_calls_this_hour.limit ?? 0}</span>
|
||||
</span>
|
||||
</div>
|
||||
<ProgressBar value={usageSummary.usage.api_calls_this_hour.usage_percentage} />
|
||||
@@ -704,89 +710,61 @@ const SubscriptionPage: React.FC = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Upgrade Modal */}
|
||||
{/* Upgrade Dialog */}
|
||||
{upgradeDialogOpen && selectedPlan && availablePlans && (
|
||||
<Modal
|
||||
<DialogModal
|
||||
isOpen={upgradeDialogOpen}
|
||||
onClose={() => setUpgradeDialogOpen(false)}
|
||||
title="Confirmar Cambio de Plan"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<p className="text-[var(--text-secondary)]">
|
||||
¿Estás seguro de que quieres cambiar tu plan de suscripción?
|
||||
</p>
|
||||
{availablePlans.plans[selectedPlan] && usageSummary && (
|
||||
<div className="p-4 bg-[var(--bg-secondary)] rounded-lg space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span>Plan actual:</span>
|
||||
<span>{usageSummary.plan}</span>
|
||||
message={
|
||||
<div className="space-y-3">
|
||||
<p>¿Estás seguro de que quieres cambiar tu plan de suscripción?</p>
|
||||
{availablePlans.plans[selectedPlan as keyof typeof availablePlans.plans] && usageSummary && (
|
||||
<div className="p-4 bg-[var(--bg-secondary)] rounded-lg space-y-2">
|
||||
<div className="flex justify-between">
|
||||
<span>Plan actual:</span>
|
||||
<span>{usageSummary.plan}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span>Nuevo plan:</span>
|
||||
<span>{availablePlans.plans[selectedPlan as keyof typeof availablePlans.plans].name}</span>
|
||||
</div>
|
||||
<div className="flex justify-between font-medium">
|
||||
<span>Nuevo precio:</span>
|
||||
<span>{subscriptionService.formatPrice(availablePlans.plans[selectedPlan as keyof typeof availablePlans.plans].monthly_price)}/mes</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span>Nuevo plan:</span>
|
||||
<span>{availablePlans.plans[selectedPlan].name}</span>
|
||||
</div>
|
||||
<div className="flex justify-between font-medium">
|
||||
<span>Nuevo precio:</span>
|
||||
<span>{subscriptionService.formatPrice(availablePlans.plans[selectedPlan].monthly_price)}/mes</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2 pt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setUpgradeDialogOpen(false)}
|
||||
className="flex-1"
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleUpgradeConfirm}
|
||||
disabled={upgrading}
|
||||
className="flex-1"
|
||||
>
|
||||
{upgrading ? 'Procesando...' : 'Confirmar Cambio'}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
}
|
||||
type="confirm"
|
||||
onConfirm={handleUpgradeConfirm}
|
||||
onCancel={() => setUpgradeDialogOpen(false)}
|
||||
confirmLabel="Confirmar Cambio"
|
||||
cancelLabel="Cancelar"
|
||||
loading={upgrading}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Cancellation Modal */}
|
||||
{/* Cancellation Dialog */}
|
||||
{cancellationDialogOpen && (
|
||||
<Modal
|
||||
<DialogModal
|
||||
isOpen={cancellationDialogOpen}
|
||||
onClose={() => setCancellationDialogOpen(false)}
|
||||
title="Cancelar Suscripción"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<p className="text-[var(--text-secondary)]">
|
||||
¿Estás seguro de que deseas cancelar tu suscripción? Esta acción no se puede deshacer.
|
||||
</p>
|
||||
<p className="text-[var(--text-secondary)]">
|
||||
Perderás acceso a las funcionalidades premium al final del período de facturación actual.
|
||||
</p>
|
||||
|
||||
<div className="flex gap-2 pt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setCancellationDialogOpen(false)}
|
||||
className="flex-1"
|
||||
>
|
||||
Volver
|
||||
</Button>
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={handleCancelSubscription}
|
||||
disabled={cancelling}
|
||||
className="flex-1"
|
||||
>
|
||||
{cancelling ? 'Cancelando...' : 'Confirmar Cancelación'}
|
||||
</Button>
|
||||
message={
|
||||
<div className="space-y-3">
|
||||
<p>¿Estás seguro de que deseas cancelar tu suscripción? Esta acción no se puede deshacer.</p>
|
||||
<p>Perderás acceso a las funcionalidades premium al final del período de facturación actual.</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
}
|
||||
type="warning"
|
||||
onConfirm={handleCancelSubscription}
|
||||
onCancel={() => setCancellationDialogOpen(false)}
|
||||
confirmLabel="Confirmar Cancelación"
|
||||
cancelLabel="Volver"
|
||||
loading={cancelling}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user