'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'; import { Header } from '@/components/layouts/header'; import { Card, CardContent, CardHeader, CardTitle, Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@horux/shared-ui'; import { getMyTenants, addMyTenant, type MyTenantDetailed } from '@/lib/api/tenants'; import { switchTenant } from '@/lib/api/auth'; import { useAuthStore } from '@/stores/auth-store'; import { formatCurrency } from '@/lib/utils'; import { Building2, Plus, Crown, ArrowRight, Loader2, AlertCircle, CheckCircle2 } from 'lucide-react'; const PLAN_LABELS: Record = { starter: 'Starter', business: 'Business', business_ia: 'Business + IA', custom: 'Custom', enterprise: 'Enterprise', }; const STATUS_BADGES: Record = { authorized: { label: 'Activa', className: 'bg-green-100 text-green-700 border-green-200' }, trial: { label: 'Prueba', className: 'bg-blue-100 text-blue-700 border-blue-200' }, trial_converted: { label: 'Activa', className: 'bg-green-100 text-green-700 border-green-200' }, trial_expired: { label: 'Prueba vencida', className: 'bg-amber-100 text-amber-700 border-amber-200' }, pending: { label: 'Pendiente de pago', className: 'bg-amber-100 text-amber-700 border-amber-200' }, paused: { label: 'Pausada', className: 'bg-slate-100 text-slate-700 border-slate-200' }, cancelled: { label: 'Cancelada', className: 'bg-red-100 text-red-700 border-red-200' }, }; export default function MisEmpresasPage() { const router = useRouter(); const queryClient = useQueryClient(); const { user, setUser, setTokens } = useAuthStore(); const [addOpen, setAddOpen] = useState(false); const [form, setForm] = useState({ nombre: '', rfc: '', plan: 'starter' as const }); const [error, setError] = useState(null); const { data: tenants = [], isLoading } = useQuery({ queryKey: ['my-tenants'], queryFn: getMyTenants, }); const addMutation = useMutation({ mutationFn: addMyTenant, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['my-tenants'] }); setAddOpen(false); setForm({ nombre: '', rfc: '', plan: 'starter' }); setError(null); }, onError: (err: any) => { setError(err?.response?.data?.message || 'Error al agregar empresa'); }, }); const handleSwitch = async (tenantId: string) => { if (tenantId === user?.tenantId) { router.push('/dashboard'); return; } try { const res = await switchTenant(tenantId); setTokens(res.accessToken, res.refreshToken); setUser(res.user); queryClient.clear(); router.push('/dashboard'); window.location.reload(); } catch (err: any) { alert(err?.response?.data?.message || 'Error al cambiar de empresa'); } }; const handleGoSuscripcion = async (tenantId: string) => { if (tenantId !== user?.tenantId) { await handleSwitch(tenantId); // tras el reload el router pierde control return; } router.push('/configuracion/suscripcion'); }; return ( <>

Empresas que tienes bajo tu cuenta. Cada empresa tiene su propia suscripción y datos fiscales. Usa el dropdown del header o el botón "Ir a esta empresa" para cambiar de contexto.

{isLoading ? (
Cargando...
) : tenants.length === 0 ? (

No tienes empresas registradas.

) : (
{tenants.map(t => ( handleSwitch(t.tenantId)} onGoSuscripcion={() => handleGoSuscripcion(t.tenantId)} /> ))}
)} { if (!addMutation.isPending) setAddOpen(open); }}> Agregar empresa Registra una empresa adicional bajo tu cuenta. Te volverás owner automáticamente. Al terminar, se te redirigirá a la página de contratación de plan.
{ e.preventDefault(); setError(null); addMutation.mutate(form); }} className="space-y-4 py-2" >
setForm({ ...form, nombre: e.target.value })} required minLength={2} />
setForm({ ...form, rfc: e.target.value.toUpperCase() })} required minLength={12} maxLength={13} className="font-mono uppercase" placeholder="XAXX010101000" />

Se contratará desde la nueva empresa. Sin prueba — los RFCs adicionales requieren plan directo.

{error && (
{error}
)}
); } interface TenantCardProps { tenant: MyTenantDetailed; isActive: boolean; onSwitch: () => void; onGoSuscripcion: () => void; } function TenantCard({ tenant, isActive, onSwitch, onGoSuscripcion }: TenantCardProps) { const sub = tenant.subscription; const statusBadge = sub ? STATUS_BADGES[sub.status] || { label: sub.status, className: 'bg-slate-100 text-slate-700 border-slate-200' } : null; return (
{tenant.nombre} {tenant.isOwner && }

{tenant.rfc}

{isActive && ( Activa )}

Plan

{PLAN_LABELS[tenant.plan] || tenant.plan}

{statusBadge && (

Estado

{statusBadge.label}
)} {sub?.amount && sub.amount > 0 && (

{sub.frequency === 'annual' ? 'Anual' : 'Mensual'}

{formatCurrency(sub.amount)}

)}
{sub?.currentPeriodEnd && (

Próximo cobro: {new Date(sub.currentPeriodEnd).toLocaleDateString('es-MX')}

)} {sub?.pendingPlan && sub?.pendingEffectiveAt && (

Cambio a {PLAN_LABELS[sub.pendingPlan] || sub.pendingPlan} programado para {new Date(sub.pendingEffectiveAt).toLocaleDateString('es-MX')}

)}
{!isActive && ( )}
); }