143 lines
4 KiB
TypeScript
143 lines
4 KiB
TypeScript
import { ApiRequestOptions } from '../hooks/useApi';
|
|
|
|
// ============================================================================
|
|
// TYPES — aligned with State Machine (wiki/concepts/Subscription-State-Machine.md)
|
|
// ============================================================================
|
|
|
|
export type SubscriptionStatus = 'PENDING' | 'SCHEDULED' | 'TRIALING' | 'ACTIVE' | 'PAST_DUE' | 'EXPIRED';
|
|
export type BillingPeriod = 'MONTHLY' | 'YEARLY' | 'NONE';
|
|
|
|
export interface SubscriptionPlan {
|
|
planKey: string;
|
|
selectableByUser: boolean;
|
|
title: Record<string, string>;
|
|
description: Record<string, string>;
|
|
currency: string;
|
|
billingPeriod: BillingPeriod;
|
|
pricePerUserCHF: number;
|
|
pricePerFeatureInstanceCHF: number;
|
|
autoRenew: boolean;
|
|
maxUsers: number | null;
|
|
maxFeatureInstances: number | null;
|
|
trialDays: number | null;
|
|
successorPlanKey: string | null;
|
|
}
|
|
|
|
export interface MandateSubscription {
|
|
id: string;
|
|
mandateId: string;
|
|
planKey: string;
|
|
status: SubscriptionStatus;
|
|
recurring: boolean;
|
|
startedAt: string;
|
|
effectiveFrom: string | null;
|
|
endedAt: string | null;
|
|
currentPeriodStart: string | null;
|
|
currentPeriodEnd: string | null;
|
|
trialEndsAt: string | null;
|
|
snapshotPricePerUserCHF: number;
|
|
snapshotPricePerInstanceCHF: number;
|
|
stripeSubscriptionId: string | null;
|
|
}
|
|
|
|
export interface SubscriptionStatusResponse {
|
|
active: boolean;
|
|
subscription: MandateSubscription | null;
|
|
plan: SubscriptionPlan | null;
|
|
scheduled: MandateSubscription | null;
|
|
}
|
|
|
|
export interface ActivatePlanResponse {
|
|
redirectUrl?: string;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
export type ApiRequestFunction = (options: ApiRequestOptions<any>) => Promise<any>;
|
|
|
|
// ============================================================================
|
|
// Helpers
|
|
// ============================================================================
|
|
|
|
function _mandateConfig(mandateId?: string): Record<string, any> {
|
|
if (!mandateId) return {};
|
|
return { headers: { 'X-Mandate-Id': mandateId } };
|
|
}
|
|
|
|
// ============================================================================
|
|
// API FUNCTIONS
|
|
// ============================================================================
|
|
|
|
export async function fetchSelectablePlans(
|
|
request: ApiRequestFunction,
|
|
mandateId?: string,
|
|
): Promise<SubscriptionPlan[]> {
|
|
return await request({
|
|
url: '/api/subscription/plans',
|
|
method: 'get',
|
|
additionalConfig: _mandateConfig(mandateId),
|
|
});
|
|
}
|
|
|
|
export async function fetchSubscriptionStatus(
|
|
request: ApiRequestFunction,
|
|
mandateId?: string,
|
|
): Promise<SubscriptionStatusResponse> {
|
|
return await request({
|
|
url: '/api/subscription/status',
|
|
method: 'get',
|
|
additionalConfig: _mandateConfig(mandateId),
|
|
});
|
|
}
|
|
|
|
export async function activatePlan(
|
|
request: ApiRequestFunction,
|
|
planKey: string,
|
|
mandateId?: string,
|
|
returnUrl?: string,
|
|
): Promise<ActivatePlanResponse> {
|
|
return await request({
|
|
url: '/api/subscription/activate',
|
|
method: 'post',
|
|
data: { planKey, returnUrl: returnUrl || '' },
|
|
additionalConfig: _mandateConfig(mandateId),
|
|
});
|
|
}
|
|
|
|
export async function cancelSubscription(
|
|
request: ApiRequestFunction,
|
|
subscriptionId: string,
|
|
mandateId?: string,
|
|
): Promise<Record<string, unknown>> {
|
|
return await request({
|
|
url: '/api/subscription/cancel',
|
|
method: 'post',
|
|
data: { subscriptionId },
|
|
additionalConfig: _mandateConfig(mandateId),
|
|
});
|
|
}
|
|
|
|
export async function reactivateSubscription(
|
|
request: ApiRequestFunction,
|
|
subscriptionId: string,
|
|
mandateId?: string,
|
|
): Promise<Record<string, unknown>> {
|
|
return await request({
|
|
url: '/api/subscription/reactivate',
|
|
method: 'post',
|
|
data: { subscriptionId },
|
|
additionalConfig: _mandateConfig(mandateId),
|
|
});
|
|
}
|
|
|
|
export async function verifyCheckout(
|
|
request: ApiRequestFunction,
|
|
sessionId: string,
|
|
mandateId?: string,
|
|
): Promise<{ status: string; message: string }> {
|
|
return await request({
|
|
url: '/api/subscription/checkout/verify',
|
|
method: 'post',
|
|
data: { sessionId },
|
|
additionalConfig: _mandateConfig(mandateId),
|
|
});
|
|
}
|