@umituz/react-native-subscription 1.1.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -23
- package/src/index.ts +50 -19
- package/src/presentation/hooks/__tests__/useUserTier.authenticated.test.ts +79 -0
- package/src/presentation/hooks/__tests__/useUserTier.guest.test.ts +70 -0
- package/src/presentation/hooks/__tests__/useUserTier.states.test.ts +167 -0
- package/src/presentation/hooks/usePremiumGate.ts +116 -0
- package/src/presentation/hooks/useUserTier.ts +78 -0
- package/src/presentation/hooks/useUserTierWithRepository.ts +171 -0
- package/src/utils/__tests__/authUtils.test.ts +52 -0
- package/src/utils/__tests__/edgeCases.test.ts +84 -0
- package/src/utils/__tests__/premiumUtils.test.ts +178 -0
- package/src/utils/__tests__/tierUtils.test.ts +148 -0
- package/src/utils/__tests__/validation.test.ts +108 -0
- package/src/utils/authUtils.ts +65 -0
- package/src/utils/premiumAsyncUtils.ts +60 -0
- package/src/utils/premiumStatusUtils.ts +79 -0
- package/src/utils/premiumUtils.ts +9 -0
- package/src/utils/tierUtils.ts +97 -0
- package/src/utils/types.ts +37 -0
- package/src/utils/userTierUtils.ts +81 -0
- package/src/utils/validation.ts +119 -0
- package/lib/application/ports/ISubscriptionRepository.d.ts +0 -25
- package/lib/application/ports/ISubscriptionRepository.d.ts.map +0 -1
- package/lib/application/ports/ISubscriptionRepository.js +0 -9
- package/lib/application/ports/ISubscriptionRepository.js.map +0 -1
- package/lib/application/ports/ISubscriptionService.d.ts +0 -28
- package/lib/application/ports/ISubscriptionService.d.ts.map +0 -1
- package/lib/application/ports/ISubscriptionService.js +0 -6
- package/lib/application/ports/ISubscriptionService.js.map +0 -1
- package/lib/domain/entities/SubscriptionStatus.d.ts +0 -31
- package/lib/domain/entities/SubscriptionStatus.d.ts.map +0 -1
- package/lib/domain/entities/SubscriptionStatus.js +0 -39
- package/lib/domain/entities/SubscriptionStatus.js.map +0 -1
- package/lib/domain/errors/SubscriptionError.d.ts +0 -18
- package/lib/domain/errors/SubscriptionError.d.ts.map +0 -1
- package/lib/domain/errors/SubscriptionError.js +0 -30
- package/lib/domain/errors/SubscriptionError.js.map +0 -1
- package/lib/domain/value-objects/SubscriptionConfig.d.ts +0 -15
- package/lib/domain/value-objects/SubscriptionConfig.d.ts.map +0 -1
- package/lib/domain/value-objects/SubscriptionConfig.js +0 -6
- package/lib/domain/value-objects/SubscriptionConfig.js.map +0 -1
- package/lib/index.d.ts +0 -33
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -43
- package/lib/index.js.map +0 -1
- package/lib/infrastructure/services/ActivationHandler.d.ts +0 -20
- package/lib/infrastructure/services/ActivationHandler.d.ts.map +0 -1
- package/lib/infrastructure/services/ActivationHandler.js +0 -71
- package/lib/infrastructure/services/ActivationHandler.js.map +0 -1
- package/lib/infrastructure/services/SubscriptionService.d.ts +0 -22
- package/lib/infrastructure/services/SubscriptionService.d.ts.map +0 -1
- package/lib/infrastructure/services/SubscriptionService.js +0 -110
- package/lib/infrastructure/services/SubscriptionService.js.map +0 -1
- package/lib/presentation/hooks/useSubscription.d.ts +0 -33
- package/lib/presentation/hooks/useSubscription.d.ts.map +0 -1
- package/lib/presentation/hooks/useSubscription.js +0 -129
- package/lib/presentation/hooks/useSubscription.js.map +0 -1
- package/lib/utils/dateUtils.d.ts +0 -39
- package/lib/utils/dateUtils.d.ts.map +0 -1
- package/lib/utils/dateUtils.js +0 -117
- package/lib/utils/dateUtils.js.map +0 -1
- package/lib/utils/dateValidationUtils.d.ts +0 -20
- package/lib/utils/dateValidationUtils.d.ts.map +0 -1
- package/lib/utils/dateValidationUtils.js +0 -39
- package/lib/utils/dateValidationUtils.js.map +0 -1
- package/lib/utils/periodUtils.d.ts +0 -38
- package/lib/utils/periodUtils.d.ts.map +0 -1
- package/lib/utils/periodUtils.js +0 -70
- package/lib/utils/periodUtils.js.map +0 -1
- package/lib/utils/planDetectionUtils.d.ts +0 -17
- package/lib/utils/planDetectionUtils.d.ts.map +0 -1
- package/lib/utils/planDetectionUtils.js +0 -31
- package/lib/utils/planDetectionUtils.js.map +0 -1
- package/lib/utils/priceUtils.d.ts +0 -23
- package/lib/utils/priceUtils.d.ts.map +0 -1
- package/lib/utils/priceUtils.js +0 -29
- package/lib/utils/priceUtils.js.map +0 -1
- package/lib/utils/subscriptionConstants.d.ts +0 -62
- package/lib/utils/subscriptionConstants.d.ts.map +0 -1
- package/lib/utils/subscriptionConstants.js +0 -61
- package/lib/utils/subscriptionConstants.js.map +0 -1
- package/src/utils/dateUtils.test.ts +0 -116
- package/src/utils/dateUtils.ts +0 -147
- package/src/utils/periodUtils.ts +0 -104
- package/src/utils/planDetectionUtils.test.ts +0 -47
- package/src/utils/planDetectionUtils.ts +0 -40
- package/src/utils/priceUtils.test.ts +0 -35
- package/src/utils/priceUtils.ts +0 -31
- package/src/utils/subscriptionConstants.ts +0 -70
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useSubscription Hook
|
|
3
|
-
* React hook for subscription management
|
|
4
|
-
*/
|
|
5
|
-
import { useState, useCallback } from 'react';
|
|
6
|
-
import { getSubscriptionService } from '../../infrastructure/services/SubscriptionService';
|
|
7
|
-
/**
|
|
8
|
-
* Hook for subscription operations
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```typescript
|
|
12
|
-
* const { status, isPremium, loadStatus } = useSubscription();
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
|
-
export function useSubscription() {
|
|
16
|
-
const [status, setStatus] = useState(null);
|
|
17
|
-
const [loading, setLoading] = useState(false);
|
|
18
|
-
const [error, setError] = useState(null);
|
|
19
|
-
const loadStatus = useCallback(async (userId) => {
|
|
20
|
-
if (!userId) {
|
|
21
|
-
setError('User ID is required');
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const service = getSubscriptionService();
|
|
25
|
-
if (!service) {
|
|
26
|
-
setError('Subscription service is not initialized');
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
setLoading(true);
|
|
30
|
-
setError(null);
|
|
31
|
-
try {
|
|
32
|
-
const subscriptionStatus = await service.getSubscriptionStatus(userId);
|
|
33
|
-
setStatus(subscriptionStatus);
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to load subscription status';
|
|
37
|
-
setError(errorMessage);
|
|
38
|
-
}
|
|
39
|
-
finally {
|
|
40
|
-
setLoading(false);
|
|
41
|
-
}
|
|
42
|
-
}, []);
|
|
43
|
-
const refreshStatus = useCallback(async (userId) => {
|
|
44
|
-
if (!userId) {
|
|
45
|
-
setError('User ID is required');
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const service = getSubscriptionService();
|
|
49
|
-
if (!service) {
|
|
50
|
-
setError('Subscription service is not initialized');
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
setLoading(true);
|
|
54
|
-
setError(null);
|
|
55
|
-
try {
|
|
56
|
-
const subscriptionStatus = await service.getSubscriptionStatus(userId);
|
|
57
|
-
setStatus(subscriptionStatus);
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to refresh subscription status';
|
|
61
|
-
setError(errorMessage);
|
|
62
|
-
}
|
|
63
|
-
finally {
|
|
64
|
-
setLoading(false);
|
|
65
|
-
}
|
|
66
|
-
}, []);
|
|
67
|
-
const activateSubscription = useCallback(async (userId, productId, expiresAt) => {
|
|
68
|
-
if (!userId || !productId) {
|
|
69
|
-
setError('User ID and Product ID are required');
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const service = getSubscriptionService();
|
|
73
|
-
if (!service) {
|
|
74
|
-
setError('Subscription service is not initialized');
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
setLoading(true);
|
|
78
|
-
setError(null);
|
|
79
|
-
try {
|
|
80
|
-
const updatedStatus = await service.activateSubscription(userId, productId, expiresAt);
|
|
81
|
-
setStatus(updatedStatus);
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to activate subscription';
|
|
85
|
-
setError(errorMessage);
|
|
86
|
-
throw err;
|
|
87
|
-
}
|
|
88
|
-
finally {
|
|
89
|
-
setLoading(false);
|
|
90
|
-
}
|
|
91
|
-
}, []);
|
|
92
|
-
const deactivateSubscription = useCallback(async (userId) => {
|
|
93
|
-
if (!userId) {
|
|
94
|
-
setError('User ID is required');
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
const service = getSubscriptionService();
|
|
98
|
-
if (!service) {
|
|
99
|
-
setError('Subscription service is not initialized');
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
setLoading(true);
|
|
103
|
-
setError(null);
|
|
104
|
-
try {
|
|
105
|
-
const updatedStatus = await service.deactivateSubscription(userId);
|
|
106
|
-
setStatus(updatedStatus);
|
|
107
|
-
}
|
|
108
|
-
catch (err) {
|
|
109
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to deactivate subscription';
|
|
110
|
-
setError(errorMessage);
|
|
111
|
-
throw err;
|
|
112
|
-
}
|
|
113
|
-
finally {
|
|
114
|
-
setLoading(false);
|
|
115
|
-
}
|
|
116
|
-
}, []);
|
|
117
|
-
const isPremium = status?.isPremium && (status.expiresAt === null || new Date(status.expiresAt).getTime() > Date.now()) || false;
|
|
118
|
-
return {
|
|
119
|
-
status,
|
|
120
|
-
loading,
|
|
121
|
-
error,
|
|
122
|
-
isPremium,
|
|
123
|
-
loadStatus,
|
|
124
|
-
refreshStatus,
|
|
125
|
-
activateSubscription,
|
|
126
|
-
deactivateSubscription,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
//# sourceMappingURL=useSubscription.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useSubscription.js","sourceRoot":"","sources":["../../../src/presentation/hooks/useSubscription.ts"],"names":[],"mappings":"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"}
|
package/lib/utils/dateUtils.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Utilities
|
|
3
|
-
* Subscription date-related helper functions
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only date formatting and calculation
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Format expiration date for display
|
|
12
|
-
*/
|
|
13
|
-
export declare function formatExpirationDate(expiresAt: string | null, locale?: string): string | null;
|
|
14
|
-
/**
|
|
15
|
-
* Calculate expiration date based on subscription plan
|
|
16
|
-
*
|
|
17
|
-
* This function handles:
|
|
18
|
-
* - RevenueCat sandbox accelerated timers (detects and recalculates)
|
|
19
|
-
* - Production dates (trusts RevenueCat's date if valid)
|
|
20
|
-
* - Monthly subscriptions: Same day next month (e.g., Nov 10 → Dec 10)
|
|
21
|
-
* - Yearly subscriptions: Same day next year (e.g., Nov 10, 2024 → Nov 10, 2025)
|
|
22
|
-
* - Weekly subscriptions: +7 days
|
|
23
|
-
*
|
|
24
|
-
* @param productId - Product identifier (e.g., "com.company.app.monthly")
|
|
25
|
-
* @param revenueCatExpiresAt - Optional expiration date from RevenueCat API
|
|
26
|
-
* @returns ISO date string for expiration, or null if invalid
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* // Monthly subscription purchased on Nov 10, 2024
|
|
30
|
-
* calculateExpirationDate('com.company.app.monthly', null)
|
|
31
|
-
* // Returns: '2024-12-10T...' (Dec 10, 2024)
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* // Yearly subscription purchased on Nov 10, 2024
|
|
35
|
-
* calculateExpirationDate('com.company.app.yearly', null)
|
|
36
|
-
* // Returns: '2025-11-10T...' (Nov 10, 2025)
|
|
37
|
-
*/
|
|
38
|
-
export declare function calculateExpirationDate(productId: string | null | undefined, revenueCatExpiresAt?: string | null): string | null;
|
|
39
|
-
//# sourceMappingURL=dateUtils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dateUtils.d.ts","sourceRoot":"","sources":["../../src/utils/dateUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,GAAE,MAAsC,GAC7C,MAAM,GAAG,IAAI,CAkBf;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACpC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAClC,MAAM,GAAG,IAAI,CA0Ef"}
|
package/lib/utils/dateUtils.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Utilities
|
|
3
|
-
* Subscription date-related helper functions
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only date formatting and calculation
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
import { DATE_CONSTANTS } from './subscriptionConstants';
|
|
11
|
-
import { extractPlanFromProductId } from './planDetectionUtils';
|
|
12
|
-
import { SUBSCRIPTION_PLAN_TYPES, MIN_SUBSCRIPTION_DURATIONS_DAYS, SUBSCRIPTION_PERIOD_DAYS, } from './subscriptionConstants';
|
|
13
|
-
/**
|
|
14
|
-
* Format expiration date for display
|
|
15
|
-
*/
|
|
16
|
-
export function formatExpirationDate(expiresAt, locale = DATE_CONSTANTS.DEFAULT_LOCALE) {
|
|
17
|
-
if (!expiresAt) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
const date = new Date(expiresAt);
|
|
22
|
-
if (isNaN(date.getTime())) {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
return date.toLocaleDateString(locale, {
|
|
26
|
-
year: 'numeric',
|
|
27
|
-
month: 'long',
|
|
28
|
-
day: 'numeric',
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Calculate expiration date based on subscription plan
|
|
37
|
-
*
|
|
38
|
-
* This function handles:
|
|
39
|
-
* - RevenueCat sandbox accelerated timers (detects and recalculates)
|
|
40
|
-
* - Production dates (trusts RevenueCat's date if valid)
|
|
41
|
-
* - Monthly subscriptions: Same day next month (e.g., Nov 10 → Dec 10)
|
|
42
|
-
* - Yearly subscriptions: Same day next year (e.g., Nov 10, 2024 → Nov 10, 2025)
|
|
43
|
-
* - Weekly subscriptions: +7 days
|
|
44
|
-
*
|
|
45
|
-
* @param productId - Product identifier (e.g., "com.company.app.monthly")
|
|
46
|
-
* @param revenueCatExpiresAt - Optional expiration date from RevenueCat API
|
|
47
|
-
* @returns ISO date string for expiration, or null if invalid
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* // Monthly subscription purchased on Nov 10, 2024
|
|
51
|
-
* calculateExpirationDate('com.company.app.monthly', null)
|
|
52
|
-
* // Returns: '2024-12-10T...' (Dec 10, 2024)
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* // Yearly subscription purchased on Nov 10, 2024
|
|
56
|
-
* calculateExpirationDate('com.company.app.yearly', null)
|
|
57
|
-
* // Returns: '2025-11-10T...' (Nov 10, 2025)
|
|
58
|
-
*/
|
|
59
|
-
export function calculateExpirationDate(productId, revenueCatExpiresAt) {
|
|
60
|
-
if (!productId)
|
|
61
|
-
return null;
|
|
62
|
-
const plan = extractPlanFromProductId(productId);
|
|
63
|
-
const now = new Date();
|
|
64
|
-
// Check if RevenueCat's date is valid and not sandbox accelerated
|
|
65
|
-
if (revenueCatExpiresAt) {
|
|
66
|
-
try {
|
|
67
|
-
const rcDate = new Date(revenueCatExpiresAt);
|
|
68
|
-
// Only trust if date is in the future
|
|
69
|
-
if (rcDate > now) {
|
|
70
|
-
// Detect sandbox accelerated timers by checking duration
|
|
71
|
-
const durationMs = rcDate.getTime() - now.getTime();
|
|
72
|
-
const durationDays = durationMs / DATE_CONSTANTS.MILLISECONDS_PER_DAY;
|
|
73
|
-
// Get minimum expected duration for this plan type
|
|
74
|
-
const minDurationMap = {
|
|
75
|
-
[SUBSCRIPTION_PLAN_TYPES.WEEKLY]: MIN_SUBSCRIPTION_DURATIONS_DAYS.WEEKLY,
|
|
76
|
-
[SUBSCRIPTION_PLAN_TYPES.MONTHLY]: MIN_SUBSCRIPTION_DURATIONS_DAYS.MONTHLY,
|
|
77
|
-
[SUBSCRIPTION_PLAN_TYPES.YEARLY]: MIN_SUBSCRIPTION_DURATIONS_DAYS.YEARLY,
|
|
78
|
-
[SUBSCRIPTION_PLAN_TYPES.UNKNOWN]: MIN_SUBSCRIPTION_DURATIONS_DAYS.UNKNOWN,
|
|
79
|
-
};
|
|
80
|
-
const minDuration = minDurationMap[plan];
|
|
81
|
-
// If duration is reasonable, trust RevenueCat's date (production)
|
|
82
|
-
if (durationDays >= minDuration) {
|
|
83
|
-
return rcDate.toISOString();
|
|
84
|
-
}
|
|
85
|
-
// Otherwise, fall through to manual calculation (sandbox accelerated)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// Invalid date, fall through to calculation
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
// Calculate production-equivalent expiration date
|
|
93
|
-
// Use current date as base to preserve the day of month/year
|
|
94
|
-
const calculatedDate = new Date(now);
|
|
95
|
-
switch (plan) {
|
|
96
|
-
case SUBSCRIPTION_PLAN_TYPES.WEEKLY:
|
|
97
|
-
// Weekly: +7 days
|
|
98
|
-
calculatedDate.setDate(calculatedDate.getDate() + SUBSCRIPTION_PERIOD_DAYS.WEEKLY);
|
|
99
|
-
break;
|
|
100
|
-
case SUBSCRIPTION_PLAN_TYPES.MONTHLY:
|
|
101
|
-
// Monthly: Same day next month
|
|
102
|
-
// This handles edge cases like Jan 31 → Feb 28/29 correctly
|
|
103
|
-
calculatedDate.setMonth(calculatedDate.getMonth() + 1);
|
|
104
|
-
break;
|
|
105
|
-
case SUBSCRIPTION_PLAN_TYPES.YEARLY:
|
|
106
|
-
// Yearly: Same day next year
|
|
107
|
-
// This handles leap years correctly (Feb 29 → Feb 28/29)
|
|
108
|
-
calculatedDate.setFullYear(calculatedDate.getFullYear() + 1);
|
|
109
|
-
break;
|
|
110
|
-
default:
|
|
111
|
-
// Unknown plan type - default to 1 month
|
|
112
|
-
calculatedDate.setMonth(calculatedDate.getMonth() + 1);
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
return calculatedDate.toISOString();
|
|
116
|
-
}
|
|
117
|
-
//# sourceMappingURL=dateUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dateUtils.js","sourceRoot":"","sources":["../../src/utils/dateUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Validation Utilities
|
|
3
|
-
* Utilities for validating and checking subscription dates
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only date validation logic
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
import type { SubscriptionStatus } from '../domain/entities/SubscriptionStatus';
|
|
11
|
-
/**
|
|
12
|
-
* Check if subscription is expired
|
|
13
|
-
*/
|
|
14
|
-
export declare function isSubscriptionExpired(status: SubscriptionStatus | null): boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Get days until subscription expires
|
|
17
|
-
* Returns null for lifetime subscriptions
|
|
18
|
-
*/
|
|
19
|
-
export declare function getDaysUntilExpiration(status: SubscriptionStatus | null): number | null;
|
|
20
|
-
//# sourceMappingURL=dateValidationUtils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dateValidationUtils.d.ts","sourceRoot":"","sources":["../../src/utils/dateValidationUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAEhF;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,kBAAkB,GAAG,IAAI,GAChC,OAAO,CAcT;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,kBAAkB,GAAG,IAAI,GAChC,MAAM,GAAG,IAAI,CAaf"}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Date Validation Utilities
|
|
3
|
-
* Utilities for validating and checking subscription dates
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only date validation logic
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Check if subscription is expired
|
|
12
|
-
*/
|
|
13
|
-
export function isSubscriptionExpired(status) {
|
|
14
|
-
if (!status || !status.isPremium) {
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
if (!status.expiresAt) {
|
|
18
|
-
// Lifetime subscription (no expiration)
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
const expirationDate = new Date(status.expiresAt);
|
|
22
|
-
const now = new Date();
|
|
23
|
-
return expirationDate.getTime() <= now.getTime();
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Get days until subscription expires
|
|
27
|
-
* Returns null for lifetime subscriptions
|
|
28
|
-
*/
|
|
29
|
-
export function getDaysUntilExpiration(status) {
|
|
30
|
-
if (!status || !status.expiresAt) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
const expirationDate = new Date(status.expiresAt);
|
|
34
|
-
const now = new Date();
|
|
35
|
-
const diffMs = expirationDate.getTime() - now.getTime();
|
|
36
|
-
const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
|
|
37
|
-
return Math.max(0, diffDays);
|
|
38
|
-
}
|
|
39
|
-
//# sourceMappingURL=dateValidationUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dateValidationUtils.js","sourceRoot":"","sources":["../../src/utils/dateValidationUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAiC;IAEjC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,wCAAwC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,OAAO,cAAc,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAiC;IAEjC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACxB,MAAM,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAC/B,CAAC;IAEF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Period Utilities
|
|
3
|
-
* Subscription period-related helper functions
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only period-related operations
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Get subscription period text from RevenueCat package
|
|
12
|
-
* Extracts readable period text from PurchasesPackage or subscription period object
|
|
13
|
-
*
|
|
14
|
-
* @param input - RevenueCat PurchasesPackage or subscription period object
|
|
15
|
-
* @returns Human-readable period text (e.g., "month", "year", "2 months")
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // From PurchasesPackage
|
|
19
|
-
* getPeriodText(pkg) // Returns: "month"
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* // From subscription period object
|
|
23
|
-
* getPeriodText({ unit: "MONTH", numberOfUnits: 1 }) // Returns: "month"
|
|
24
|
-
* getPeriodText({ unit: "YEAR", numberOfUnits: 1 }) // Returns: "year"
|
|
25
|
-
* getPeriodText({ unit: "MONTH", numberOfUnits: 3 }) // Returns: "3 months"
|
|
26
|
-
*/
|
|
27
|
-
export declare function getPeriodText(input: {
|
|
28
|
-
product?: {
|
|
29
|
-
subscriptionPeriod?: {
|
|
30
|
-
unit: string;
|
|
31
|
-
numberOfUnits: number;
|
|
32
|
-
} | string | null;
|
|
33
|
-
};
|
|
34
|
-
} | {
|
|
35
|
-
unit: string;
|
|
36
|
-
numberOfUnits: number;
|
|
37
|
-
} | null | undefined): string;
|
|
38
|
-
//# sourceMappingURL=periodUtils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"periodUtils.d.ts","sourceRoot":"","sources":["../../src/utils/periodUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EACD;IACE,OAAO,CAAC,EAAE;QACR,kBAAkB,CAAC,EACf;YACE,IAAI,EAAE,MAAM,CAAC;YACb,aAAa,EAAE,MAAM,CAAC;SACvB,GACD,MAAM,GACN,IAAI,CAAC;KACV,CAAC;CACH,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB,GACD,IAAI,GACJ,SAAS,GACZ,MAAM,CAsDR"}
|
package/lib/utils/periodUtils.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Period Utilities
|
|
3
|
-
* Subscription period-related helper functions
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only period-related operations
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
import { SUBSCRIPTION_PERIOD_UNITS } from './subscriptionConstants';
|
|
11
|
-
/**
|
|
12
|
-
* Get subscription period text from RevenueCat package
|
|
13
|
-
* Extracts readable period text from PurchasesPackage or subscription period object
|
|
14
|
-
*
|
|
15
|
-
* @param input - RevenueCat PurchasesPackage or subscription period object
|
|
16
|
-
* @returns Human-readable period text (e.g., "month", "year", "2 months")
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* // From PurchasesPackage
|
|
20
|
-
* getPeriodText(pkg) // Returns: "month"
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* // From subscription period object
|
|
24
|
-
* getPeriodText({ unit: "MONTH", numberOfUnits: 1 }) // Returns: "month"
|
|
25
|
-
* getPeriodText({ unit: "YEAR", numberOfUnits: 1 }) // Returns: "year"
|
|
26
|
-
* getPeriodText({ unit: "MONTH", numberOfUnits: 3 }) // Returns: "3 months"
|
|
27
|
-
*/
|
|
28
|
-
export function getPeriodText(input) {
|
|
29
|
-
if (!input)
|
|
30
|
-
return '';
|
|
31
|
-
// Extract subscription period from PurchasesPackage or use directly
|
|
32
|
-
let subscriptionPeriod;
|
|
33
|
-
// Check if input is PurchasesPackage (has product property)
|
|
34
|
-
if ('product' in input && input.product?.subscriptionPeriod) {
|
|
35
|
-
const period = input.product.subscriptionPeriod;
|
|
36
|
-
// Type guard: check if period is an object with unit and numberOfUnits
|
|
37
|
-
// RevenueCat's subscriptionPeriod can be string | null | object
|
|
38
|
-
if (typeof period === 'object' &&
|
|
39
|
-
period !== null &&
|
|
40
|
-
'unit' in period &&
|
|
41
|
-
'numberOfUnits' in period) {
|
|
42
|
-
subscriptionPeriod = {
|
|
43
|
-
unit: period.unit,
|
|
44
|
-
numberOfUnits: period.numberOfUnits,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
// If period is string, we can't extract unit/numberOfUnits, return empty
|
|
48
|
-
}
|
|
49
|
-
else if ('unit' in input && 'numberOfUnits' in input) {
|
|
50
|
-
// Input is already a subscription period object
|
|
51
|
-
subscriptionPeriod = {
|
|
52
|
-
unit: input.unit,
|
|
53
|
-
numberOfUnits: input.numberOfUnits,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
if (!subscriptionPeriod)
|
|
57
|
-
return '';
|
|
58
|
-
const { unit, numberOfUnits } = subscriptionPeriod;
|
|
59
|
-
if (unit === SUBSCRIPTION_PERIOD_UNITS.MONTH) {
|
|
60
|
-
return numberOfUnits === 1 ? 'month' : `${numberOfUnits} months`;
|
|
61
|
-
}
|
|
62
|
-
if (unit === SUBSCRIPTION_PERIOD_UNITS.YEAR) {
|
|
63
|
-
return numberOfUnits === 1 ? 'year' : `${numberOfUnits} years`;
|
|
64
|
-
}
|
|
65
|
-
if (unit === SUBSCRIPTION_PERIOD_UNITS.WEEK) {
|
|
66
|
-
return numberOfUnits === 1 ? 'week' : `${numberOfUnits} weeks`;
|
|
67
|
-
}
|
|
68
|
-
return '';
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=periodUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"periodUtils.js","sourceRoot":"","sources":["../../src/utils/periodUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEpE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAC3B,KAiBa;IAEb,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,oEAAoE;IACpE,IAAI,kBAMS,CAAC;IAEd,4DAA4D;IAC5D,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC;QAC5D,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;QAChD,uEAAuE;QACvE,gEAAgE;QAChE,IACE,OAAO,MAAM,KAAK,QAAQ;YAC1B,MAAM,KAAK,IAAI;YACf,MAAM,IAAI,MAAM;YAChB,eAAe,IAAI,MAAM,EACzB,CAAC;YACD,kBAAkB,GAAG;gBACnB,IAAI,EAAE,MAAM,CAAC,IAAc;gBAC3B,aAAa,EAAE,MAAM,CAAC,aAAuB;aAC9C,CAAC;QACJ,CAAC;QACD,yEAAyE;IAC3E,CAAC;SAAM,IAAI,MAAM,IAAI,KAAK,IAAI,eAAe,IAAI,KAAK,EAAE,CAAC;QACvD,gDAAgD;QAChD,kBAAkB,GAAG;YACnB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,aAAa,EAAE,KAAK,CAAC,aAAa;SACnC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,kBAAkB;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,kBAAkB,CAAC;IAEnD,IAAI,IAAI,KAAK,yBAAyB,CAAC,KAAK,EAAE,CAAC;QAC7C,OAAO,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,aAAa,SAAS,CAAC;IACnE,CAAC;IAED,IAAI,IAAI,KAAK,yBAAyB,CAAC,IAAI,EAAE,CAAC;QAC5C,OAAO,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,aAAa,QAAQ,CAAC;IACjE,CAAC;IAED,IAAI,IAAI,KAAK,yBAAyB,CAAC,IAAI,EAAE,CAAC;QAC5C,OAAO,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,aAAa,QAAQ,CAAC;IACjE,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan Detection Utilities
|
|
3
|
-
* Utilities for detecting subscription plan types from product IDs
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only plan detection logic
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
import { type SubscriptionPlanType } from './subscriptionConstants';
|
|
11
|
-
/**
|
|
12
|
-
* Extract subscription plan type from product ID
|
|
13
|
-
* Example: "com.company.app.weekly" → "weekly"
|
|
14
|
-
* @internal
|
|
15
|
-
*/
|
|
16
|
-
export declare function extractPlanFromProductId(productId: string | null | undefined): SubscriptionPlanType;
|
|
17
|
-
//# sourceMappingURL=planDetectionUtils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"planDetectionUtils.d.ts","sourceRoot":"","sources":["../../src/utils/planDetectionUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,oBAAoB,CAgBtB"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan Detection Utilities
|
|
3
|
-
* Utilities for detecting subscription plan types from product IDs
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only plan detection logic
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
import { SUBSCRIPTION_PLAN_TYPES, PRODUCT_ID_KEYWORDS, } from './subscriptionConstants';
|
|
11
|
-
/**
|
|
12
|
-
* Extract subscription plan type from product ID
|
|
13
|
-
* Example: "com.company.app.weekly" → "weekly"
|
|
14
|
-
* @internal
|
|
15
|
-
*/
|
|
16
|
-
export function extractPlanFromProductId(productId) {
|
|
17
|
-
if (!productId)
|
|
18
|
-
return SUBSCRIPTION_PLAN_TYPES.UNKNOWN;
|
|
19
|
-
const lower = productId.toLowerCase();
|
|
20
|
-
if (PRODUCT_ID_KEYWORDS.WEEKLY.some((keyword) => lower.includes(keyword))) {
|
|
21
|
-
return SUBSCRIPTION_PLAN_TYPES.WEEKLY;
|
|
22
|
-
}
|
|
23
|
-
if (PRODUCT_ID_KEYWORDS.MONTHLY.some((keyword) => lower.includes(keyword))) {
|
|
24
|
-
return SUBSCRIPTION_PLAN_TYPES.MONTHLY;
|
|
25
|
-
}
|
|
26
|
-
if (PRODUCT_ID_KEYWORDS.YEARLY.some((keyword) => lower.includes(keyword))) {
|
|
27
|
-
return SUBSCRIPTION_PLAN_TYPES.YEARLY;
|
|
28
|
-
}
|
|
29
|
-
return SUBSCRIPTION_PLAN_TYPES.UNKNOWN;
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=planDetectionUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"planDetectionUtils.js","sourceRoot":"","sources":["../../src/utils/planDetectionUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,uBAAuB,EACvB,mBAAmB,GAEpB,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAAoC;IAEpC,IAAI,CAAC,SAAS;QAAE,OAAO,uBAAuB,CAAC,OAAO,CAAC;IAEvD,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IAEtC,IAAI,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC1E,OAAO,uBAAuB,CAAC,MAAM,CAAC;IACxC,CAAC;IACD,IAAI,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC3E,OAAO,uBAAuB,CAAC,OAAO,CAAC;IACzC,CAAC;IACD,IAAI,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC1E,OAAO,uBAAuB,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,OAAO,uBAAuB,CAAC,OAAO,CAAC;AACzC,CAAC"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Price Utilities
|
|
3
|
-
* Subscription price-related helper functions
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only price-related operations
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Format price for display
|
|
12
|
-
* Formats a price value with currency code using Intl.NumberFormat
|
|
13
|
-
*
|
|
14
|
-
* @param price - Price value (e.g., 9.99)
|
|
15
|
-
* @param currencyCode - ISO 4217 currency code (e.g., "USD", "EUR", "TRY")
|
|
16
|
-
* @returns Formatted price string (e.g., "$9.99", "€9.99", "₺9.99")
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* formatPrice(9.99, "USD") // Returns: "$9.99"
|
|
20
|
-
* formatPrice(229.99, "TRY") // Returns: "₺229.99"
|
|
21
|
-
*/
|
|
22
|
-
export declare function formatPrice(price: number, currencyCode: string): string;
|
|
23
|
-
//# sourceMappingURL=priceUtils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"priceUtils.d.ts","sourceRoot":"","sources":["../../src/utils/priceUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAKvE"}
|
package/lib/utils/priceUtils.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Price Utilities
|
|
3
|
-
* Subscription price-related helper functions
|
|
4
|
-
*
|
|
5
|
-
* Following SOLID, DRY, KISS principles:
|
|
6
|
-
* - Single Responsibility: Only price-related operations
|
|
7
|
-
* - DRY: No code duplication
|
|
8
|
-
* - KISS: Simple, clear implementations
|
|
9
|
-
*/
|
|
10
|
-
import { DATE_CONSTANTS } from './subscriptionConstants';
|
|
11
|
-
/**
|
|
12
|
-
* Format price for display
|
|
13
|
-
* Formats a price value with currency code using Intl.NumberFormat
|
|
14
|
-
*
|
|
15
|
-
* @param price - Price value (e.g., 9.99)
|
|
16
|
-
* @param currencyCode - ISO 4217 currency code (e.g., "USD", "EUR", "TRY")
|
|
17
|
-
* @returns Formatted price string (e.g., "$9.99", "€9.99", "₺9.99")
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* formatPrice(9.99, "USD") // Returns: "$9.99"
|
|
21
|
-
* formatPrice(229.99, "TRY") // Returns: "₺229.99"
|
|
22
|
-
*/
|
|
23
|
-
export function formatPrice(price, currencyCode) {
|
|
24
|
-
return new Intl.NumberFormat(DATE_CONSTANTS.DEFAULT_LOCALE, {
|
|
25
|
-
style: 'currency',
|
|
26
|
-
currency: currencyCode,
|
|
27
|
-
}).format(price);
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=priceUtils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"priceUtils.js","sourceRoot":"","sources":["../../src/utils/priceUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,YAAoB;IAC7D,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,cAAc,EAAE;QAC1D,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,YAAY;KACvB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC"}
|