Phase 3 & Phase 4 - Completed
This commit is contained in:
@@ -1126,3 +1126,289 @@ export async function getDashboardStats(params?: { site_id?: number; days?: numb
|
||||
const query = searchParams.toString();
|
||||
return fetchAPI(`/v1/account/dashboard/stats/${query ? `?${query}` : ''}`);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STRIPE INTEGRATION
|
||||
// ============================================================================
|
||||
|
||||
export interface StripeConfig {
|
||||
publishable_key: string;
|
||||
is_sandbox: boolean;
|
||||
}
|
||||
|
||||
export interface StripeCheckoutSession {
|
||||
checkout_url: string;
|
||||
session_id: string;
|
||||
}
|
||||
|
||||
export interface StripeBillingPortalSession {
|
||||
portal_url: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Stripe publishable key for frontend initialization
|
||||
*/
|
||||
export async function getStripeConfig(): Promise<StripeConfig> {
|
||||
return fetchAPI('/v1/billing/stripe/config/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Stripe Checkout session for plan subscription
|
||||
* Redirects user to Stripe's hosted checkout page
|
||||
*/
|
||||
export async function createStripeCheckout(planId: string, options?: {
|
||||
success_url?: string;
|
||||
cancel_url?: string;
|
||||
}): Promise<StripeCheckoutSession> {
|
||||
return fetchAPI('/v1/billing/stripe/checkout/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
plan_id: planId,
|
||||
...options,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Stripe Checkout session for credit package purchase
|
||||
* Redirects user to Stripe's hosted checkout page
|
||||
*/
|
||||
export async function createStripeCreditCheckout(packageId: string, options?: {
|
||||
success_url?: string;
|
||||
cancel_url?: string;
|
||||
}): Promise<StripeCheckoutSession> {
|
||||
return fetchAPI('/v1/billing/stripe/credit-checkout/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
package_id: packageId,
|
||||
...options,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Stripe Billing Portal session for subscription management
|
||||
* Allows customers to manage payment methods, view invoices, cancel subscription
|
||||
*/
|
||||
export async function openStripeBillingPortal(options?: {
|
||||
return_url?: string;
|
||||
}): Promise<StripeBillingPortalSession> {
|
||||
return fetchAPI('/v1/billing/stripe/billing-portal/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PAYPAL INTEGRATION
|
||||
// ============================================================================
|
||||
|
||||
export interface PayPalConfig {
|
||||
client_id: string;
|
||||
is_sandbox: boolean;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
export interface PayPalOrder {
|
||||
order_id: string;
|
||||
status: string;
|
||||
approval_url: string;
|
||||
links?: Array<{ rel: string; href: string }>;
|
||||
credit_package_id?: string;
|
||||
credit_amount?: number;
|
||||
plan_id?: string;
|
||||
plan_name?: string;
|
||||
}
|
||||
|
||||
export interface PayPalCaptureResult {
|
||||
order_id: string;
|
||||
status: string;
|
||||
capture_id: string;
|
||||
amount: string;
|
||||
currency: string;
|
||||
credits_added?: number;
|
||||
new_balance?: number;
|
||||
subscription_id?: string;
|
||||
plan_name?: string;
|
||||
payment_id?: number;
|
||||
}
|
||||
|
||||
export interface PayPalSubscription {
|
||||
subscription_id: string;
|
||||
status: string;
|
||||
approval_url: string;
|
||||
links?: Array<{ rel: string; href: string }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PayPal client ID for frontend initialization
|
||||
*/
|
||||
export async function getPayPalConfig(): Promise<PayPalConfig> {
|
||||
return fetchAPI('/v1/billing/paypal/config/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PayPal order for credit package purchase
|
||||
* Returns approval URL for PayPal redirect
|
||||
*/
|
||||
export async function createPayPalCreditOrder(packageId: string, options?: {
|
||||
return_url?: string;
|
||||
cancel_url?: string;
|
||||
}): Promise<PayPalOrder> {
|
||||
return fetchAPI('/v1/billing/paypal/create-order/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
package_id: packageId,
|
||||
...options,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PayPal order for plan subscription (one-time payment model)
|
||||
* Returns approval URL for PayPal redirect
|
||||
*/
|
||||
export async function createPayPalSubscriptionOrder(planId: string, options?: {
|
||||
return_url?: string;
|
||||
cancel_url?: string;
|
||||
}): Promise<PayPalOrder> {
|
||||
return fetchAPI('/v1/billing/paypal/create-subscription-order/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
plan_id: planId,
|
||||
...options,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture PayPal order after user approval
|
||||
* Call this when user returns from PayPal with approved order
|
||||
*/
|
||||
export async function capturePayPalOrder(orderId: string, options?: {
|
||||
package_id?: string;
|
||||
plan_id?: string;
|
||||
}): Promise<PayPalCaptureResult> {
|
||||
return fetchAPI('/v1/billing/paypal/capture-order/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
order_id: orderId,
|
||||
...options,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create PayPal recurring subscription
|
||||
* Requires plan to have paypal_plan_id configured
|
||||
*/
|
||||
export async function createPayPalSubscription(planId: string, options?: {
|
||||
return_url?: string;
|
||||
cancel_url?: string;
|
||||
}): Promise<PayPalSubscription> {
|
||||
return fetchAPI('/v1/billing/paypal/create-subscription/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
plan_id: planId,
|
||||
...options,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// PAYMENT GATEWAY HELPERS
|
||||
// ============================================================================
|
||||
|
||||
export type PaymentGateway = 'stripe' | 'paypal' | 'manual';
|
||||
|
||||
/**
|
||||
* Helper to check if Stripe is configured
|
||||
*/
|
||||
export async function isStripeConfigured(): Promise<boolean> {
|
||||
try {
|
||||
const config = await getStripeConfig();
|
||||
return !!config.publishable_key;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to check if PayPal is configured
|
||||
*/
|
||||
export async function isPayPalConfigured(): Promise<boolean> {
|
||||
try {
|
||||
const config = await getPayPalConfig();
|
||||
return !!config.client_id;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available payment gateways
|
||||
*/
|
||||
export async function getAvailablePaymentGateways(): Promise<{
|
||||
stripe: boolean;
|
||||
paypal: boolean;
|
||||
manual: boolean;
|
||||
}> {
|
||||
const [stripeAvailable, paypalAvailable] = await Promise.all([
|
||||
isStripeConfigured(),
|
||||
isPayPalConfigured(),
|
||||
]);
|
||||
|
||||
return {
|
||||
stripe: stripeAvailable,
|
||||
paypal: paypalAvailable,
|
||||
manual: true, // Manual payment is always available
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to plan using preferred payment gateway
|
||||
*/
|
||||
export async function subscribeToPlan(
|
||||
planId: string,
|
||||
gateway: PaymentGateway,
|
||||
options?: { return_url?: string; cancel_url?: string }
|
||||
): Promise<{ redirect_url: string }> {
|
||||
switch (gateway) {
|
||||
case 'stripe': {
|
||||
const session = await createStripeCheckout(planId, options);
|
||||
return { redirect_url: session.checkout_url };
|
||||
}
|
||||
case 'paypal': {
|
||||
const order = await createPayPalSubscriptionOrder(planId, options);
|
||||
return { redirect_url: order.approval_url };
|
||||
}
|
||||
case 'manual':
|
||||
throw new Error('Manual payment requires different flow - use submitManualPayment()');
|
||||
default:
|
||||
throw new Error(`Unsupported payment gateway: ${gateway}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purchase credit package using preferred payment gateway
|
||||
*/
|
||||
export async function purchaseCredits(
|
||||
packageId: string,
|
||||
gateway: PaymentGateway,
|
||||
options?: { return_url?: string; cancel_url?: string }
|
||||
): Promise<{ redirect_url: string }> {
|
||||
switch (gateway) {
|
||||
case 'stripe': {
|
||||
const session = await createStripeCreditCheckout(packageId, options);
|
||||
return { redirect_url: session.checkout_url };
|
||||
}
|
||||
case 'paypal': {
|
||||
const order = await createPayPalCreditOrder(packageId, options);
|
||||
return { redirect_url: order.approval_url };
|
||||
}
|
||||
case 'manual':
|
||||
throw new Error('Manual payment requires different flow - use submitManualPayment()');
|
||||
default:
|
||||
throw new Error(`Unsupported payment gateway: ${gateway}`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user