@@ -4,6 +4,11 @@ const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000
44
55class PaymentService {
66 constructor ( ) {
7+ // Cache for pricing data to avoid repeated API calls
8+ this . pricingCache = null
9+ this . pricingCacheExpiry = null
10+ this . CACHE_DURATION = 5 * 60 * 1000 // 5 minutes
11+
712 this . api = axios . create ( {
813 baseURL : API_BASE_URL ,
914 headers : {
@@ -26,47 +31,106 @@ class PaymentService {
2631 return config
2732 } )
2833
29- // Handle response errors
34+ // Handle response errors with retry logic for rate limiting
3035 this . api . interceptors . response . use (
3136 ( response ) => response . data ,
3237 ( error ) => {
33- const message = error . response ?. data ?. message || error . message || 'An error occurred'
34- throw new Error ( message )
38+ const enhancedError = new Error ( error . response ?. data ?. message || error . message || 'An error occurred' )
39+ enhancedError . status = error . response ?. status
40+ enhancedError . response = error . response
41+ enhancedError . retryAfter = error . response ?. data ?. retryAfter
42+ throw enhancedError
3543 }
3644 )
3745 }
3846
39- // Create payment order
47+ // Helper method to handle retries for rate limiting
48+ async makeRequestWithRetry ( requestFn , retryCount = 0 , maxRetries = 3 ) {
49+ try {
50+ return await requestFn ( )
51+ } catch ( error ) {
52+ // Handle rate limiting (HTTP 429)
53+ if ( error . status === 429 && retryCount < maxRetries ) {
54+ const retryAfter = error . retryAfter || Math . pow ( 2 , retryCount + 1 ) // Exponential backoff
55+ const delayMs = retryAfter * 1000
56+
57+ console . warn ( `[PaymentService] Rate limited (429). Retrying after ${ delayMs } ms... (attempt ${ retryCount + 1 } /${ maxRetries } )` )
58+
59+ await new Promise ( resolve => setTimeout ( resolve , delayMs ) )
60+ return this . makeRequestWithRetry ( requestFn , retryCount + 1 , maxRetries )
61+ }
62+
63+ // For 429 errors that exceed max retries, provide user-friendly message
64+ if ( error . status === 429 ) {
65+ const userFriendlyError = new Error ( 'Too many requests. Please wait a moment and try again.' )
66+ userFriendlyError . status = 429
67+ userFriendlyError . isRateLimit = true
68+ throw userFriendlyError
69+ }
70+
71+ throw error
72+ }
73+ }
74+
75+ // Create payment order with retry logic
4076 async createOrder ( amount , planId ) {
41- const response = await this . api . post ( '/payment/create-order' , {
42- amount,
43- planId
77+ return this . makeRequestWithRetry ( async ( ) => {
78+ const response = await this . api . post ( '/payment/create-order' , {
79+ amount,
80+ planId
81+ } )
82+ return response
4483 } )
45- return response
4684 }
4785
48- // Get international pricing based on user's location
86+ // Get international pricing with caching and retry logic
4987 async getInternationalPricing ( ) {
50- const response = await this . api . get ( '/payment/pricing' )
51- return response
88+ // Check cache first
89+ if ( this . pricingCache && this . pricingCacheExpiry && Date . now ( ) < this . pricingCacheExpiry ) {
90+ console . log ( '[PaymentService] Returning cached pricing data' )
91+ return this . pricingCache
92+ }
93+
94+ return this . makeRequestWithRetry ( async ( ) => {
95+ const response = await this . api . get ( '/payment/pricing' )
96+
97+ // Cache the response
98+ this . pricingCache = response
99+ this . pricingCacheExpiry = Date . now ( ) + this . CACHE_DURATION
100+
101+ return response
102+ } )
52103 }
53104
54- // Verify payment
105+ // Verify payment with retry logic
55106 async verifyPayment ( paymentData ) {
56- const response = await this . api . post ( '/payment/verify' , paymentData )
57- return response
107+ return this . makeRequestWithRetry ( async ( ) => {
108+ const response = await this . api . post ( '/payment/verify' , paymentData )
109+ return response
110+ } )
58111 }
59112
60- // Get payment history
113+ // Get payment history with retry logic
61114 async getPaymentHistory ( ) {
62- const response = await this . api . get ( '/payment/history' )
63- return response . payments
115+ return this . makeRequestWithRetry ( async ( ) => {
116+ const response = await this . api . get ( '/payment/history' )
117+ return response . payments
118+ } )
64119 }
65120
66- // Cancel subscription
121+ // Cancel subscription with retry logic
67122 async cancelSubscription ( ) {
68- const response = await this . api . post ( '/payment/cancel-subscription' )
69- return response
123+ return this . makeRequestWithRetry ( async ( ) => {
124+ const response = await this . api . post ( '/payment/cancel-subscription' )
125+ return response
126+ } )
127+ }
128+
129+ // Clear pricing cache (useful for testing or manual refresh)
130+ clearPricingCache ( ) {
131+ this . pricingCache = null
132+ this . pricingCacheExpiry = null
133+ console . log ( '[PaymentService] Pricing cache cleared' )
70134 }
71135}
72136
0 commit comments