- Updated the BTCPay service to support internal Lightning invoices with private route hints, improving payment routing for users with private channels. - Added reconciliation methods for pending rents and subscriptions to ensure missed payments are processed on startup. - Enhanced the rental and subscription services to handle payments in satoshis, aligning with Lightning Network standards. - Improved the rental modal and content detail components to display rental status and pricing more clearly, including a countdown for rental expiration. - Refactored various components to streamline user experience and ensure accurate rental access checks.
127 lines
3.2 KiB
TypeScript
127 lines
3.2 KiB
TypeScript
import { apiService } from './api.service'
|
|
import type { ApiSubscription } from '../types/api'
|
|
|
|
/**
|
|
* Subscription Service
|
|
* Handles user subscriptions
|
|
*/
|
|
class SubscriptionService {
|
|
/**
|
|
* Get user's subscriptions
|
|
*/
|
|
async getSubscriptions(): Promise<ApiSubscription[]> {
|
|
return apiService.get<ApiSubscription[]>('/subscriptions')
|
|
}
|
|
|
|
/**
|
|
* Get active subscription
|
|
*/
|
|
async getActiveSubscription(): Promise<ApiSubscription | null> {
|
|
const subscriptions = await this.getSubscriptions()
|
|
return subscriptions.find((sub) => sub.status === 'active') || null
|
|
}
|
|
|
|
/**
|
|
* Subscribe to a tier
|
|
*/
|
|
async subscribe(data: {
|
|
tier: 'enthusiast' | 'film-buff' | 'cinephile'
|
|
period: 'monthly' | 'annual'
|
|
paymentMethodId?: string
|
|
}): Promise<ApiSubscription> {
|
|
return apiService.post<ApiSubscription>('/subscriptions', data)
|
|
}
|
|
|
|
/**
|
|
* Cancel subscription
|
|
*/
|
|
async cancelSubscription(subscriptionId: string): Promise<void> {
|
|
await apiService.delete(`/subscriptions/${subscriptionId}`)
|
|
}
|
|
|
|
/**
|
|
* Resume cancelled subscription
|
|
*/
|
|
async resumeSubscription(subscriptionId: string): Promise<ApiSubscription> {
|
|
return apiService.post<ApiSubscription>(`/subscriptions/${subscriptionId}/resume`)
|
|
}
|
|
|
|
/**
|
|
* Create a Lightning subscription invoice via BTCPay.
|
|
* Returns invoice details including BOLT11 for QR code display.
|
|
*/
|
|
async createLightningSubscription(data: {
|
|
type: 'enthusiast' | 'film-buff' | 'cinephile'
|
|
period: 'monthly' | 'yearly'
|
|
}): Promise<{
|
|
lnInvoice: string
|
|
expiration: string
|
|
sourceAmount: { amount: string; currency: string }
|
|
id: string
|
|
}> {
|
|
return apiService.post('/subscriptions/lightning', data)
|
|
}
|
|
|
|
/**
|
|
* Update payment method
|
|
*/
|
|
async updatePaymentMethod(subscriptionId: string, paymentMethodId: string): Promise<void> {
|
|
await apiService.patch(`/subscriptions/${subscriptionId}/payment-method`, {
|
|
paymentMethodId,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Get subscription tiers with pricing (in sats)
|
|
*/
|
|
async getSubscriptionTiers(): Promise<Array<{
|
|
tier: string
|
|
name: string
|
|
monthlyPrice: number
|
|
annualPrice: number
|
|
features: string[]
|
|
}>> {
|
|
return [
|
|
{
|
|
tier: 'enthusiast',
|
|
name: 'Enthusiast',
|
|
monthlyPrice: 10000,
|
|
annualPrice: 100000,
|
|
features: [
|
|
'Access to all films and series',
|
|
'HD streaming',
|
|
'Watch on 2 devices',
|
|
],
|
|
},
|
|
{
|
|
tier: 'film-buff',
|
|
name: 'Film Buff',
|
|
monthlyPrice: 21000,
|
|
annualPrice: 210000,
|
|
features: [
|
|
'Everything in Enthusiast',
|
|
'4K streaming',
|
|
'Watch on 4 devices',
|
|
'Exclusive behind-the-scenes content',
|
|
'Early access to new releases',
|
|
],
|
|
},
|
|
{
|
|
tier: 'cinephile',
|
|
name: 'Cinephile',
|
|
monthlyPrice: 42000,
|
|
annualPrice: 420000,
|
|
features: [
|
|
'Everything in Film Buff',
|
|
'Watch on unlimited devices',
|
|
'Offline downloads',
|
|
'Director commentary tracks',
|
|
'Support independent filmmakers',
|
|
],
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
export const subscriptionService = new SubscriptionService()
|