// Resolves the customer admin's active workspace (tenant) + its subscription // from the cached /api/me payload, and derives the license/billing figures the // /admin surface needs. One round-trip (shared with useMe's cache) backs the // whole admin shell. // // Scope note: this resolves the signed-in user's OWN tenant (tenants[0]). The // partner "acting-as a customer" path uses the partner-scoped endpoints + // usePartnerMode().activeCustomer instead, so it isn't handled here. import type { SubscriptionDoc, TenantDoc } from '~/types/workspace' const PLAN_LABEL: Record = { mvp: 'Starter', pro: 'Business', enterprise: 'Enterprise', } // Subscription amounts are stored in MINOR units (øre/cents) and per BILLING // CYCLE, not per month. This mirrors platform-api's normalizeToMonthly (used by // the MRR/partner-billing aggregations) so the portal shows the same figures. function cycleToMonthlyMinor(perCycleMinor: number, cycle: string): number { if (cycle === 'quarterly') return Math.round(perCycleMinor / 3) if (cycle === 'yearly') return Math.round(perCycleMinor / 12) return perCycleMinor } export function useTenant() { const { state, fetchMe } = useMe() // A user can technically belong to several tenants; the admin surface acts on // the first. Refine to an explicit picker if multi-tenant admins land later. const tenant = computed(() => state.value?.tenants?.[0] ?? null) const subscription = computed(() => { const t = tenant.value const subs = state.value?.subscriptions ?? [] if (!t) return subs[0] ?? null return subs.find((s) => s.tenantId === t._id) ?? subs[0] ?? null }) const planKey = computed(() => subscription.value?.plan ?? tenant.value?.plan ?? 'mvp') const planLabel = computed(() => PLAN_LABEL[planKey.value] ?? planKey.value) const currency = computed(() => subscription.value?.currency ?? 'DKK') // Billed seat limit (license cap). Falls back to the tenant's seat count. const seatLimit = computed(() => subscription.value?.seats ?? tenant.value?.seats ?? 0) // Per-seat cost normalized to monthly, in MAJOR units (e.g. DKK). Drives the // add-seats modal math. const perSeatMonthly = computed(() => { const sub = subscription.value if (!sub?.perSeatAmount) return 0 return cycleToMonthlyMinor(sub.perSeatAmount, sub.cycle) / 100 }) // Monthly recurring spend = per-seat × billed seats, cycle-normalized to // monthly, converted minor → major. In `currency`. const monthlySpend = computed(() => { const sub = subscription.value if (!sub?.perSeatAmount || !sub.seats) return 0 return cycleToMonthlyMinor(sub.perSeatAmount * sub.seats, sub.cycle) / 100 }) const primaryDomain = computed(() => tenant.value?.domains?.[0] ?? null) const renewsAt = computed(() => subscription.value?.currentPeriodEnd ? new Date(subscription.value.currentPeriodEnd) : null, ) return { tenant, subscription, fetchMe, planKey, planLabel, currency, seatLimit, perSeatMonthly, monthlySpend, primaryDomain, renewsAt, } }