/** * Subscriptions API Client * * API functions for subscription and license management */ import { get, post } from './client'; /** * Subscription plan types */ export type SubscriptionPlan = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINIUM'; export type PlanFeature = | 'dashboard' | 'wiki' | 'user_management' | 'csv_export' | 'api_access' | 'custom_interface' | 'dedicated_kam'; /** * 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; maxShipmentsPerYear: number; bookingFeeEur: number; supportLevel: 'none' | 'email' | 'direct' | 'dedicated_kam'; statusBadge: 'none' | 'silver' | 'gold' | 'platinium'; planFeatures: PlanFeature[]; 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 'BRONZE': return 'bg-orange-100 text-orange-800'; case 'SILVER': return 'bg-slate-100 text-slate-800'; case 'GOLD': return 'bg-yellow-100 text-yellow-800'; case 'PLATINIUM': return 'bg-purple-100 text-purple-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'; } }