diff --git a/mvp/b2c/src/app/admin/planes/actions.ts b/mvp/b2c/src/app/admin/planes/actions.ts new file mode 100644 index 0000000..27e2bc7 --- /dev/null +++ b/mvp/b2c/src/app/admin/planes/actions.ts @@ -0,0 +1,16 @@ +'use server'; + +import { revalidatePath } from 'next/cache'; +import { requireAdmin } from '@/lib/auth/current-user'; +import { assignPlan, setSubscriptionStatus } from '@/db/admin-queries'; +import { tenants } from '@/db/schema'; + +export async function asignarPlan(formData: FormData) { + await requireAdmin(); + const tenantId = String(formData.get('tenantId')); + const planId = String(formData.get('planId')); + const status = String(formData.get('status')) as (typeof tenants.subscriptionStatus.enumValues)[number]; + await assignPlan(tenantId, planId); + await setSubscriptionStatus(tenantId, status); + revalidatePath('/admin/planes'); +} diff --git a/mvp/b2c/src/app/admin/planes/page.tsx b/mvp/b2c/src/app/admin/planes/page.tsx new file mode 100644 index 0000000..dc13e4e --- /dev/null +++ b/mvp/b2c/src/app/admin/planes/page.tsx @@ -0,0 +1,61 @@ +import { listPlans, listTenants } from '@/db/admin-queries'; +import { asignarPlan } from './actions'; +import { formatEuros } from '@/lib/funnel'; + +export const dynamic = 'force-dynamic'; + +const ESTADOS = ['trial', 'activo', 'cancelado', 'vencido'] as const; + +export default async function PlanesPage() { + const [plans, tenants] = await Promise.all([listPlans(), listTenants()]); + const nombrePlan = new Map(plans.map((p) => [p.id, p.nombre])); + return ( +
+

Planes

+ +
+ {plans.map((p) => ( +
+
+

{p.nombre}

+ {formatEuros(p.precioMensual)}/mes +
+
    + {p.features.map((f) =>
  • · {f}
  • )} +
+
+ ))} +
+ +
+ + + + + + + {tenants.map((t) => ( + + + + + + + ))} + +
ReformistaPlan actualEstadoAsignar
{t.nombreEmpresa}{t.planId ? nombrePlan.get(t.planId) ?? '—' : '—'}{t.subscriptionStatus} +
+ + + + +
+
+
+
+ ); +}