/** * Subscriptions API Client * * API functions for subscription and license management */ import { get, post } from './client'; /** * Subscription plan types */ export type SubscriptionPlan = 'FREE' | 'STARTER' | 'PRO' | 'ENTERPRISE'; /** * Subscription status types */ export type SubscriptionStatus = | 'ACTIVE' | 'PAST_DUE' | 'CANCELED' | 'INCOMPLETE' | 'INCOMPLETE_EXPIRED' | 'TRIALING' | 'UNPAID' | 'PAUSED'; /** * Billing interval types */ export type BillingInterval = 'monthly' | 'yearly'; /** * Plan details */ export interface PlanDetails { plan: SubscriptionPlan; name: string; maxLicenses: number; monthlyPriceEur: number; yearlyPriceEur: number; features: string[]; } /** * License response */ export interface LicenseResponse { id: string; userId: string; userEmail: string; userName: string; userRole: string; status: 'ACTIVE' | 'REVOKED'; assignedAt: string; revokedAt?: string; } /** * Subscription overview response */ export interface SubscriptionOverviewResponse { id: string; organizationId: string; plan: SubscriptionPlan; planDetails: PlanDetails; status: SubscriptionStatus; usedLicenses: number; maxLicenses: number; availableLicenses: number; cancelAtPeriodEnd: boolean; currentPeriodStart?: string; currentPeriodEnd?: string; createdAt: string; updatedAt: string; licenses: LicenseResponse[]; } /** * Can invite response */ export interface CanInviteResponse { canInvite: boolean; availableLicenses: number; usedLicenses: number; maxLicenses: number; message?: string; } /** * All plans response */ export interface AllPlansResponse { plans: PlanDetails[]; } /** * Checkout session request */ export interface CreateCheckoutSessionRequest { plan: SubscriptionPlan; billingInterval: BillingInterval; successUrl?: string; cancelUrl?: string; } /** * Checkout session response */ export interface CheckoutSessionResponse { sessionId: string; sessionUrl: string; } /** * Portal session request */ export interface CreatePortalSessionRequest { returnUrl?: string; } /** * Portal session response */ export interface PortalSessionResponse { sessionUrl: string; } /** * Get subscription overview for current organization */ export async function getSubscriptionOverview(): Promise { return get('/api/v1/subscriptions'); } /** * Get all available plans */ export async function getAllPlans(): Promise { return get('/api/v1/subscriptions/plans'); } /** * Check if organization can invite more users */ export async function canInviteUser(): Promise { return get('/api/v1/subscriptions/can-invite'); } /** * Create a Stripe Checkout session for subscription upgrade */ export async function createCheckoutSession( data: CreateCheckoutSessionRequest, ): Promise { return post('/api/v1/subscriptions/checkout', data); } /** * Create a Stripe Customer Portal session */ export async function createPortalSession( data?: CreatePortalSessionRequest, ): Promise { return post('/api/v1/subscriptions/portal', data || {}); } /** * Sync subscription from Stripe * Useful when webhooks are not available (e.g., local development) * @param sessionId - Optional Stripe checkout session ID (pass after checkout completes) */ export async function syncSubscriptionFromStripe(sessionId?: string): Promise { return post('/api/v1/subscriptions/sync', { sessionId }); } /** * Format price for display */ export function formatPrice(amount: number, currency = 'EUR'): string { return new Intl.NumberFormat('fr-FR', { style: 'currency', currency, minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(amount); } /** * Get plan badge color class */ export function getPlanBadgeColor(plan: SubscriptionPlan): string { switch (plan) { case 'FREE': return 'bg-gray-100 text-gray-800'; case 'STARTER': return 'bg-blue-100 text-blue-800'; case 'PRO': return 'bg-purple-100 text-purple-800'; case 'ENTERPRISE': return 'bg-amber-100 text-amber-800'; default: return 'bg-gray-100 text-gray-800'; } } /** * Get status badge color class */ export function getStatusBadgeColor(status: SubscriptionStatus): string { switch (status) { case 'ACTIVE': case 'TRIALING': return 'bg-green-100 text-green-800'; case 'PAST_DUE': return 'bg-yellow-100 text-yellow-800'; case 'CANCELED': case 'INCOMPLETE_EXPIRED': case 'UNPAID': return 'bg-red-100 text-red-800'; case 'INCOMPLETE': case 'PAUSED': return 'bg-gray-100 text-gray-800'; default: return 'bg-gray-100 text-gray-800'; } }