import { toTitleCase } from "remeda" import { renderDetailBlock } from "./detail-block" import { dimmed } from "./io" interface OrganizationDetail { activeSubscription?: { periodEnd?: Date | string | null status: string } | null createdAt: Date | string id: string limits: { aiSpendUsd: number automationRuntimeMinutes: number emailSends: number projects: number seats: number webScrapingMinutes: number } memberCount: number name: string pendingInvitationCount: number plan?: string | null projectCount: number role?: string usage: { aiSpendUsd: number automationRuntimeMs: number emailSends: number webScrapingMs: number } } /** * Renders an organization's identity, plan, usage, and billing details. * * @param org - Organization data to display. * @param options - Optional fields to include in the block. * @param options.includeRole - Whether to include the caller's role. */ export function renderOrganizationDetailBlock( org: OrganizationDetail, options: { includeRole?: boolean } = {}, ) { return renderDetailBlock( { [dimmed`Name`]: org.name, [dimmed`ID`]: dimmed(org.id), [dimmed`Created`]: formatDate(org.createdAt), [dimmed`Plan`]: getPlanName(org.plan), ...(options.includeRole && org.role ? { [dimmed`Role`]: toTitleCase(org.role) } : {}), [dimmed`Seats`]: org.plan === "pro" ? `${org.memberCount} active (${org.limits.seats} included; additional billed)` : `${org.memberCount + org.pendingInvitationCount} / ${org.limits.seats}`, [dimmed`Projects`]: `${org.projectCount} / ${org.limits.projects}`, [dimmed`AI spend`]: `${formatUsd(org.usage.aiSpendUsd)} / ${formatUsd(org.limits.aiSpendUsd)}`, [dimmed`Automation runtime`]: `${formatRuntimeMinutes(org.usage.automationRuntimeMs)} / ${formatRuntimeMinutes(org.limits.automationRuntimeMinutes * 60_000)} min`, [dimmed`Email sends`]: `${org.usage.emailSends} / ${org.limits.emailSends}`, [dimmed`Web scraping`]: `${formatRuntimeMinutes(org.usage.webScrapingMs)} / ${formatRuntimeMinutes(org.limits.webScrapingMinutes * 60_000)} min`, ...(org.activeSubscription ? { [dimmed`Billing`]: formatBillingStatus(org.activeSubscription), [dimmed`Renews`]: org.activeSubscription.periodEnd ? formatDate(org.activeSubscription.periodEnd) : null, } : {}), }, { keyAlignment: "right" }, ) } /** * Formats aggregate milliseconds without rounding individual invocations. * * @param runtimeMs - Aggregate runtime in milliseconds. */ function formatRuntimeMinutes(runtimeMs: number) { return Number.isFinite(runtimeMs) ? (runtimeMs / 60_000).toLocaleString(undefined, { maximumFractionDigits: 2, }) : "Unlimited" } /** * Formats a plan's AI spend amount for terminal output. * * @param amount - USD amount or an infinite allowance. */ function formatUsd(amount: number) { return Number.isFinite(amount) ? `$${amount.toFixed(2)}` : "Unlimited" } /** * Converts an internal plan identifier to a display name. * * @param plan - Internal plan identifier. */ function getPlanName(plan: string | null | undefined) { switch (plan) { case "enterprise": return "Enterprise" case "pro": return "Pro" default: return "Free" } } /** * Converts a subscription status to a billing label. * * @param billing - Subscription billing state. * @param billing.status - Internal subscription status identifier. */ function formatBillingStatus(billing: { status: string }) { return ( { active: "Active", canceled: "Canceled", incomplete: "Incomplete", incomplete_expired: "Incomplete", past_due: "Payment issue", paused: "Paused", trialing: "Trial", unpaid: "Payment issue", }[billing.status] ?? "Active" ) } /** * Formats a date for the user's locale. * * @param date - Date value to format. */ function formatDate(date: Date | string) { return new Date(date).toLocaleDateString() }