@umituz/react-native-subscription 2.14.96 → 2.14.98

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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +462 -0
  3. package/package.json +3 -3
  4. package/src/application/README.md +229 -0
  5. package/src/application/ports/README.md +103 -0
  6. package/src/domain/README.md +402 -0
  7. package/src/domain/constants/README.md +80 -0
  8. package/src/domain/entities/README.md +176 -0
  9. package/src/domain/errors/README.md +307 -0
  10. package/src/domain/value-objects/README.md +186 -0
  11. package/src/domains/config/README.md +390 -0
  12. package/src/domains/paywall/README.md +371 -0
  13. package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
  14. package/src/domains/paywall/components/README.md +185 -0
  15. package/src/domains/paywall/entities/README.md +199 -0
  16. package/src/domains/paywall/hooks/README.md +129 -0
  17. package/src/domains/wallet/README.md +292 -0
  18. package/src/domains/wallet/domain/README.md +108 -0
  19. package/src/domains/wallet/domain/entities/README.md +122 -0
  20. package/src/domains/wallet/domain/errors/README.md +157 -0
  21. package/src/domains/wallet/infrastructure/README.md +96 -0
  22. package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
  23. package/src/domains/wallet/presentation/components/README.md +231 -0
  24. package/src/domains/wallet/presentation/hooks/README.md +255 -0
  25. package/src/infrastructure/README.md +514 -0
  26. package/src/infrastructure/mappers/README.md +34 -0
  27. package/src/infrastructure/models/README.md +26 -0
  28. package/src/infrastructure/repositories/README.md +385 -0
  29. package/src/infrastructure/services/README.md +374 -0
  30. package/src/presentation/README.md +410 -0
  31. package/src/presentation/components/README.md +183 -0
  32. package/src/presentation/components/details/CreditRow.md +337 -0
  33. package/src/presentation/components/details/DetailRow.md +283 -0
  34. package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
  35. package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
  36. package/src/presentation/components/details/README.md +449 -0
  37. package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
  38. package/src/presentation/components/feedback/README.md +447 -0
  39. package/src/presentation/components/paywall/PaywallModal.md +444 -0
  40. package/src/presentation/components/paywall/README.md +190 -0
  41. package/src/presentation/components/sections/README.md +468 -0
  42. package/src/presentation/components/sections/SubscriptionSection.md +246 -0
  43. package/src/presentation/hooks/README.md +743 -0
  44. package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
  45. package/src/presentation/hooks/useAuthGate.md +403 -0
  46. package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
  47. package/src/presentation/hooks/useCreditChecker.md +407 -0
  48. package/src/presentation/hooks/useCredits.md +342 -0
  49. package/src/presentation/hooks/useCreditsGate.md +346 -0
  50. package/src/presentation/hooks/useDeductCredit.md +160 -0
  51. package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
  52. package/src/presentation/hooks/useFeatureGate.md +157 -0
  53. package/src/presentation/hooks/useInitializeCredits.md +458 -0
  54. package/src/presentation/hooks/usePaywall.md +334 -0
  55. package/src/presentation/hooks/usePaywallOperations.md +486 -0
  56. package/src/presentation/hooks/usePaywallVisibility.md +344 -0
  57. package/src/presentation/hooks/usePremium.md +230 -0
  58. package/src/presentation/hooks/usePremiumGate.md +423 -0
  59. package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
  60. package/src/presentation/hooks/useSubscription.md +450 -0
  61. package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
  62. package/src/presentation/hooks/useSubscriptionGate.md +168 -0
  63. package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
  64. package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
  65. package/src/presentation/hooks/useUserTier.md +356 -0
  66. package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
  67. package/src/presentation/screens/README.md +194 -0
  68. package/src/presentation/types/README.md +38 -0
  69. package/src/presentation/utils/README.md +52 -0
  70. package/src/revenuecat/README.md +523 -0
  71. package/src/revenuecat/domain/README.md +147 -0
  72. package/src/revenuecat/domain/errors/README.md +197 -0
  73. package/src/revenuecat/infrastructure/config/README.md +40 -0
  74. package/src/revenuecat/infrastructure/managers/README.md +49 -0
  75. package/src/revenuecat/presentation/hooks/README.md +56 -0
  76. package/src/revenuecat/presentation/hooks/usePurchasePackage.ts +1 -1
  77. package/src/utils/README.md +529 -0
@@ -0,0 +1,52 @@
1
+ # Presentation Utils
2
+
3
+ Utility functions and helpers for the presentation layer.
4
+
5
+ ## Overview
6
+
7
+ This directory contains utility functions used by presentation components and hooks.
8
+
9
+ ## Contents
10
+
11
+ - **subscriptionDateUtils.ts** - Date formatting and manipulation for subscription display
12
+ - **paywallUtils.ts** - Paywall-related utility functions
13
+
14
+ ## Date Utilities
15
+
16
+ ### formatDate
17
+
18
+ Format ISO date string to localized date string.
19
+
20
+ ```typescript
21
+ formatDate('2024-01-15T10:30:00Z'); // "January 15, 2024"
22
+ ```
23
+
24
+ ### calculateDaysRemaining
25
+
26
+ Calculate days between now and expiration date.
27
+
28
+ ```typescript
29
+ calculateDaysRemaining('2024-02-15T10:30:00Z'); // 31
30
+ ```
31
+
32
+ ### convertPurchasedAt
33
+
34
+ Convert purchasedAt date to ISO string.
35
+
36
+ ```typescript
37
+ convertPurchasedAt(new Date()); // "2024-01-15T10:30:00Z"
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ```typescript
43
+ import { formatDate, calculateDaysRemaining } from '../utils/subscriptionDateUtils';
44
+
45
+ const expirationDisplay = formatDate(subscription.expirationDate);
46
+ const daysLeft = calculateDaysRemaining(subscription.expirationDate);
47
+ ```
48
+
49
+ ## Related
50
+
51
+ - [Hooks](../hooks/README.md)
52
+ - [Types](../types/README.md)
@@ -0,0 +1,523 @@
1
+ # RevenueCat Integration
2
+
3
+ RevenueCat ile abonelik yönetimi için kapsamlı entegrasyon ve API wrapper.
4
+
5
+ ## Özellikler
6
+
7
+ - **Otomatik Başlatma**: RevenueCat SDK otomatik başlatma ve konfigürasyon
8
+ - **User ID Yönetimi**: Auth sistemleriyle entegre user ID yönetimi
9
+ - **Purchase Flow**: Satın alma işlemleri için yönetilen flow
10
+ - **Restore İşlemi**: Satın alma geri yükleme desteği
11
+ - **Customer Info**: Kullanıcı abonelik bilgilerini takip
12
+ - **Error Handling**: RevenueCat hatalarını yönetme
13
+
14
+ ## Kurulum
15
+
16
+ ### 1. RevenueCat SDK Kurulumu
17
+
18
+ ```bash
19
+ npm install react-native-purchases
20
+ # veya
21
+ yarn add react-native-purchases
22
+ ```
23
+
24
+ ### 2. Başlatma
25
+
26
+ ```typescript
27
+ import {
28
+ initializeSubscription,
29
+ SubscriptionInitConfig,
30
+ } from '@umituz/react-native-subscription';
31
+
32
+ const config: SubscriptionInitConfig = {
33
+ revenueCatApiKey: 'your_api_key',
34
+ revenueCatEntitlementId: 'premium',
35
+
36
+ // Opsiyonel
37
+ userDefaultsSuiteName: 'app.revenuecat',
38
+ diagnosticsEnabled: __DEV__,
39
+ };
40
+
41
+ await initializeSubscription(config);
42
+ ```
43
+
44
+ ### 3. Provider ile Kullanım
45
+
46
+ ```typescript
47
+ import { SubscriptionProvider } from '@umituz/react-native-subscription';
48
+
49
+ function App() {
50
+ return (
51
+ <SubscriptionProvider config={config}>
52
+ <YourApp />
53
+ </SubscriptionProvider>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ## Hooks
59
+
60
+ ### useRevenueCat
61
+
62
+ RevenueCat'e erişim ve temel işlemler için:
63
+
64
+ ```typescript
65
+ import { useRevenueCat } from '@umituz/react-native-subscription';
66
+
67
+ function RevenueCatExample() {
68
+ const {
69
+ isReady,
70
+ isInitialized,
71
+ error,
72
+ purchaserInfo,
73
+ offerings,
74
+ } = useRevenueCat();
75
+
76
+ if (!isInitialized) {
77
+ return <ActivityIndicator />;
78
+ }
79
+
80
+ return (
81
+ <View>
82
+ <Text>Status: {isReady ? 'Ready' : 'Loading'}</Text>
83
+ </View>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ### useCustomerInfo
89
+
90
+ Kullanıcı abonelik bilgileri için:
91
+
92
+ ```typescript
93
+ import { useCustomerInfo } from '@umituz/react-native-subscription';
94
+
95
+ function SubscriptionStatus() {
96
+ const {
97
+ customerInfo,
98
+ isLoading,
99
+ error,
100
+ refetch,
101
+ } = useCustomerInfo();
102
+
103
+ if (isLoading) return <ActivityIndicator />;
104
+
105
+ const entitlement = customerInfo?.entitlements.active['premium'];
106
+
107
+ return (
108
+ <View>
109
+ <Text>
110
+ Status: {entitlement ? 'Premium' : 'Free'}
111
+ </Text>
112
+ {entitlement && (
113
+ <Text>
114
+ Expires: {new Date(entitlement.expirationDate).toLocaleDateString()}
115
+ </Text>
116
+ )}
117
+ <Button onPress={refetch} title="Refresh" />
118
+ </View>
119
+ );
120
+ }
121
+ ```
122
+
123
+ ### useInitializeSubscription
124
+
125
+ Başlatma durumu kontrolü için:
126
+
127
+ ```typescript
128
+ import { useInitializeSubscription } from '@umituz/react-native-subscription';
129
+
130
+ function InitCheck() {
131
+ const {
132
+ isInitialized,
133
+ isInitializing,
134
+ error,
135
+ initialize,
136
+ } = useInitializeSubscription();
137
+
138
+ useEffect(() => {
139
+ if (!isInitialized && !isInitializing) {
140
+ initialize();
141
+ }
142
+ }, []);
143
+
144
+ if (isInitializing) {
145
+ return <Text>Initializing...</Text>;
146
+ }
147
+
148
+ if (error) {
149
+ return <Text>Error: {error.message}</Text>;
150
+ }
151
+
152
+ return <Text>Ready!</Text>;
153
+ }
154
+ ```
155
+
156
+ ### useSubscriptionPackages
157
+
158
+ Mevcut abonelik paketleri için:
159
+
160
+ ```typescript
161
+ import { useSubscriptionPackages } from '@umituz/react-native-subscription';
162
+
163
+ function PackageList() {
164
+ const {
165
+ packages,
166
+ offerings,
167
+ isLoading,
168
+ error,
169
+ } = useSubscriptionPackages({
170
+ offeringId: 'default',
171
+ });
172
+
173
+ if (isLoading) return <ActivityIndicator />;
174
+
175
+ return (
176
+ <ScrollView>
177
+ {packages.map((pkg) => (
178
+ <PackageCard
179
+ key={pkg.identifier}
180
+ package={pkg}
181
+ onPress={() => handlePurchase(pkg)}
182
+ />
183
+ ))}
184
+ </ScrollView>
185
+ );
186
+ }
187
+ ```
188
+
189
+ ### usePaywallFlow
190
+
191
+ Tam paywall flow'u için:
192
+
193
+ ```typescript
194
+ import { usePaywallFlow } from '@umituz/react-native-subscription';
195
+
196
+ function Paywall() {
197
+ const {
198
+ packages,
199
+ selectedPackage,
200
+ isLoading,
201
+ error,
202
+ selectPackage,
203
+ purchaseSelectedPackage,
204
+ restorePurchases,
205
+ } = usePaywallFlow();
206
+
207
+ const handlePurchase = async () => {
208
+ try {
209
+ const result = await purchaseSelectedPackage();
210
+
211
+ if (result.success) {
212
+ Alert.alert('Success', 'You are now a premium user!');
213
+ } else {
214
+ Alert.alert('Error', result.error?.message);
215
+ }
216
+ } catch (err) {
217
+ Alert.alert('Error', 'Purchase failed');
218
+ }
219
+ };
220
+
221
+ return (
222
+ <View>
223
+ {packages.map((pkg) => (
224
+ <TouchableOpacity
225
+ key={pkg.identifier}
226
+ onPress={() => selectPackage(pkg)}
227
+ style={selectedPackage?.identifier === pkg.identifier &&
228
+ styles.selected
229
+ }
230
+ >
231
+ <Text>{pkg.product.title}</Text>
232
+ <Text>{pkg.product.priceString}</Text>
233
+ </TouchableOpacity>
234
+ ))}
235
+
236
+ <Button
237
+ onPress={handlePurchase}
238
+ disabled={!selectedPackage || isLoading}
239
+ title="Subscribe"
240
+ />
241
+
242
+ <Button
243
+ onPress={restorePurchases}
244
+ disabled={isLoading}
245
+ title="Restore"
246
+ />
247
+ </View>
248
+ );
249
+ }
250
+ ```
251
+
252
+ ### useRestorePurchase
253
+
254
+ Satın alma geri yükleme için:
255
+
256
+ ```typescript
257
+ import { useRestorePurchase } from '@umituz/react-native-subscription';
258
+
259
+ function RestoreButton() {
260
+ const { restorePurchase, isLoading, error, isRestored } = useRestorePurchase();
261
+
262
+ const handleRestore = async () => {
263
+ const result = await restorePurchase();
264
+
265
+ if (result.success) {
266
+ Alert.alert('Success', 'Purchase restored!');
267
+ } else {
268
+ Alert.alert('Error', result.error?.message || 'Restore failed');
269
+ }
270
+ };
271
+
272
+ return (
273
+ <Button
274
+ onPress={handleRestore}
275
+ disabled={isLoading}
276
+ title={isLoading ? 'Restoring...' : 'Restore Purchase'}
277
+ />
278
+ );
279
+ }
280
+ ```
281
+
282
+ ## Hata Yönetimi
283
+
284
+ ### RevenueCatError
285
+
286
+ ```typescript
287
+ import {
288
+ RevenueCatError,
289
+ ErrorCode,
290
+ handleRevenueCatError,
291
+ } from '@umituz/react-native-subscription';
292
+
293
+ try {
294
+ await purchasePackage(packageToPurchase);
295
+ } catch (error) {
296
+ if (error instanceof RevenueCatError) {
297
+ switch (error.code) {
298
+ case ErrorCode.PurchaseCancelledError:
299
+ console.log('User cancelled');
300
+ break;
301
+ case ErrorCode.PurchaseInvalidError:
302
+ console.log('Invalid purchase');
303
+ break;
304
+ case ErrorCode.NetworkError:
305
+ console.log('Network error');
306
+ break;
307
+ default:
308
+ handleRevenueCatError(error);
309
+ }
310
+ }
311
+ }
312
+ ```
313
+
314
+ ## User ID Yönetimi
315
+
316
+ ### Auth ile Entegrasyon
317
+
318
+ ```typescript
319
+ import { useAuthSubscriptionSync } from '@umituz/react-native-subscription';
320
+
321
+ function AuthSync() {
322
+ const { user } = useAuth();
323
+ const { syncUserId, clearUserId } = useAuthSubscriptionSync();
324
+
325
+ useEffect(() => {
326
+ if (user?.uid) {
327
+ // Kullanıcı giriş yaptığında
328
+ syncUserId(user.uid);
329
+ } else {
330
+ // Kullanıcı çıkış yaptığında
331
+ clearUserId();
332
+ }
333
+ }, [user?.uid]);
334
+
335
+ return null;
336
+ }
337
+ ```
338
+
339
+ ### Manuel User ID
340
+
341
+ ```typescript
342
+ import { configureUserId } from '@umituz/react-native-subscription';
343
+
344
+ // Kullanıcı giriş yaptığında
345
+ await configureUserId('user-123');
346
+
347
+ // Kullanıcı çıkış yaptığında
348
+ await configureUserId(null); // veya await resetUserId()
349
+ ```
350
+
351
+ ## API Key Çözümleme
352
+
353
+ ### Environment Bazlı API Keys
354
+
355
+ ```typescript
356
+ import {
357
+ ApiKeyResolver,
358
+ resolveApiKey,
359
+ } from '@umituz/react-native-subscription';
360
+
361
+ const apiKeyResolver = new ApiKeyResolver({
362
+ development: 'dev_api_key',
363
+ production: 'prod_api_key',
364
+ });
365
+
366
+ const apiKey = apiKeyResolver.resolve(__DEV__ ? 'development' : 'production');
367
+ ```
368
+
369
+ ## SubscriptionManager
370
+
371
+ Gelişmiş işlemler için SubscriptionManager kullanımı:
372
+
373
+ ```typescript
374
+ import { SubscriptionManager } from '@umituz/react-native-subscription';
375
+
376
+ const manager = new SubscriptionManager(config);
377
+
378
+ // Başlatma
379
+ await manager.initialize(userId);
380
+
381
+ // Satın alma
382
+ const result = await manager.purchasePackage(packageToPurchase);
383
+
384
+ // Geri yükleme
385
+ const restoreResult = await manager.restorePurchases();
386
+
387
+ // Customer info
388
+ const info = await manager.getCustomerInfo();
389
+
390
+ // Offerings
391
+ const offerings = await manager.getOfferings();
392
+ ```
393
+
394
+ ## Best Practices
395
+
396
+ 1. **User ID Sync**: Auth sistemiyle user ID'leri her zaman senkronize edin
397
+ 2. **Error Handling**: TümRevenueCat işlemlerinde hata yönetimi kullanın
398
+ 3. **Loading States**: Kullanıcıya uygun loading feedback'i verin
399
+ 4. **Restore**: Her zaman "Restore Purchase" seçeneği sunun
400
+ 5. **Test Mode**: Geliştirme sırasında test mode kullanın
401
+ 6. **Debug Mode**: Production'da debug modu kapalı tutun
402
+
403
+ ## Örnek Uygulama
404
+
405
+ ```typescript
406
+ import React, { useEffect } from 'react';
407
+ import { View, Text, Button, ActivityIndicator } from 'react-native';
408
+ import {
409
+ usePaywallFlow,
410
+ useCustomerInfo,
411
+ useRestorePurchase,
412
+ } from '@umituz/react-native-subscription';
413
+
414
+ export default function SubscriptionScreen() {
415
+ const {
416
+ packages,
417
+ selectedPackage,
418
+ isLoading,
419
+ selectPackage,
420
+ purchaseSelectedPackage,
421
+ } = usePaywallFlow();
422
+
423
+ const { customerInfo, isLoading: infoLoading } = useCustomerInfo();
424
+ const { restorePurchase } = useRestorePurchase();
425
+
426
+ const entitlement = customerInfo?.entitlements.active['premium'];
427
+
428
+ const handleSubscribe = async () => {
429
+ if (!selectedPackage) return;
430
+
431
+ try {
432
+ const result = await purchaseSelectedPackage();
433
+
434
+ if (result.success) {
435
+ Alert.alert('Success', 'Welcome to Premium!');
436
+ } else {
437
+ Alert.alert('Error', result.error?.message || 'Purchase failed');
438
+ }
439
+ } catch (error) {
440
+ Alert.alert('Error', 'Something went wrong');
441
+ }
442
+ };
443
+
444
+ if (isLoading || infoLoading) {
445
+ return <ActivityIndicator />;
446
+ }
447
+
448
+ return (
449
+ <View>
450
+ {entitlement ? (
451
+ <>
452
+ <Text>You are Premium!</Text>
453
+ <Text>
454
+ Expires: {new Date(entitlement.expirationDate).toLocaleDateString()}
455
+ </Text>
456
+ </>
457
+ ) : (
458
+ <>
459
+ <Text>Choose your plan:</Text>
460
+ {packages.map((pkg) => (
461
+ <TouchableOpacity
462
+ key={pkg.identifier}
463
+ onPress={() => selectPackage(pkg)}
464
+ style={
465
+ selectedPackage?.identifier === pkg.identifier &&
466
+ styles.selected
467
+ }
468
+ >
469
+ <Text>{pkg.product.title}</Text>
470
+ <Text>{pkg.product.priceString}</Text>
471
+ <Text>{pkg.product.description}</Text>
472
+ </TouchableOpacity>
473
+ ))}
474
+
475
+ <Button
476
+ onPress={handleSubscribe}
477
+ disabled={!selectedPackage || isLoading}
478
+ title="Subscribe"
479
+ />
480
+
481
+ <Button onPress={restorePurchase} title="Restore" />
482
+ </>
483
+ )}
484
+ </View>
485
+ );
486
+ }
487
+ ```
488
+
489
+ ## Tip Tanımlamaları
490
+
491
+ ```typescript
492
+ interface RevenueCatConfig {
493
+ apiKey: string;
494
+ entitlements: {
495
+ premium: string;
496
+ };
497
+ userDefaultsSuiteName?: string;
498
+ diagnosticsEnabled?: boolean;
499
+ }
500
+
501
+ interface PurchaseResult {
502
+ success: boolean;
503
+ error?: Error;
504
+ customerInfo?: CustomerInfo;
505
+ }
506
+
507
+ interface CustomerInfo {
508
+ entitlements: {
509
+ active: Record<string, EntitlementInfo>;
510
+ all: Record<string, EntitlementInfo>;
511
+ };
512
+ activeSubscriptions: string[];
513
+ allPurchasedProductIdentifiers: string[];
514
+ latestExpirationDate: string;
515
+ }
516
+
517
+ interface Package {
518
+ identifier: string;
519
+ packageType: PACKAGE_TYPE;
520
+ product: Product;
521
+ offeringIdentifier: string;
522
+ }
523
+ ```
@@ -0,0 +1,147 @@
1
+ # RevenueCat Domain
2
+
3
+ Domain entities and types for RevenueCat integration.
4
+
5
+ ## Overview
6
+
7
+ This directory contains domain-specific entities representing RevenueCat concepts like entitlements, offerings, and packages.
8
+
9
+ ## Entities
10
+
11
+ ### EntitlementInfo
12
+ Represents a RevenueCat entitlement.
13
+
14
+ ```typescript
15
+ interface EntitlementInfo {
16
+ identifier: string;
17
+ isActive: boolean;
18
+ willRenew: boolean;
19
+ expirationDate?: Date;
20
+ productIdentifier?: string;
21
+ period?: PackagePeriod;
22
+ }
23
+ ```
24
+
25
+ **Usage:**
26
+ ```typescript
27
+ const entitlement: EntitlementInfo = {
28
+ identifier: 'premium',
29
+ isActive: true,
30
+ willRenew: true,
31
+ expirationDate: new Date('2024-12-31'),
32
+ productIdentifier: 'com.app.premium.annual',
33
+ period: 'annual',
34
+ };
35
+ ```
36
+
37
+ ### OfferingInfo
38
+ Represents a RevenueCat offering containing packages.
39
+
40
+ ```typescript
41
+ interface OfferingInfo {
42
+ identifier: string;
43
+ packages: PackageInfo[];
44
+ lifetime?: PackageInfo;
45
+ monthly?: PackageInfo;
46
+ annual?: PackageInfo;
47
+ }
48
+ ```
49
+
50
+ ### PackageInfo
51
+ Represents a purchasable package.
52
+
53
+ ```typescript
54
+ interface PackageInfo {
55
+ identifier: string;
56
+ packageType: PackageType;
57
+ product: ProductInfo;
58
+ offeringIdentifier: string;
59
+ }
60
+
61
+ interface ProductInfo {
62
+ identifier: string;
63
+ title: string;
64
+ description: string;
65
+ price: number;
66
+ pricePerMonth?: number;
67
+ currencyCode: string;
68
+ }
69
+
70
+ type PackageType = 'WEEKLY' | 'MONTHLY' | 'THREE_MONTHLY' | 'SIX_MONTHLY' | 'ANNUAL' | 'LIFETIME';
71
+ ```
72
+
73
+ ## Constants
74
+
75
+ ### Entitlement Identifiers
76
+
77
+ ```typescript
78
+ export const ENTITLEMENT_IDS = {
79
+ PREMIUM: 'premium',
80
+ PRO: 'pro',
81
+ BASIC: 'basic',
82
+ } as const;
83
+ ```
84
+
85
+ ### Package Periods
86
+
87
+ ```typescript
88
+ export const PACKAGE_PERIODS = {
89
+ WEEKLY: 'weekly',
90
+ MONTHLY: 'monthly',
91
+ ANNUAL: 'annual',
92
+ LIFETIME: 'lifetime',
93
+ } as const;
94
+ ```
95
+
96
+ ## Helper Functions
97
+
98
+ ### Get Package Period
99
+
100
+ ```typescript
101
+ function getPackagePeriod(packageType: PackageType): PackagePeriod {
102
+ const periodMap: Record<PackageType, PackagePeriod> = {
103
+ WEEKLY: 'monthly',
104
+ MONTHLY: 'monthly',
105
+ THREE_MONTHLY: 'monthly',
106
+ SIX_MONTHLY: 'monthly',
107
+ ANNUAL: 'annual',
108
+ LIFETIME: 'lifetime',
109
+ };
110
+ return periodMap[packageType];
111
+ }
112
+ ```
113
+
114
+ ### Calculate Price Per Month
115
+
116
+ ```typescript
117
+ function calculatePricePerMonth(packageInfo: PackageInfo): number | null {
118
+ if (!packageInfo.product.pricePerMonth) {
119
+ return packageInfo.product.price;
120
+ }
121
+ return packageInfo.product.pricePerMonth;
122
+ }
123
+ ```
124
+
125
+ ### Format Price
126
+
127
+ ```typescript
128
+ function formatPrice(price: number, currencyCode: string): string {
129
+ return new Intl.NumberFormat('en-US', {
130
+ style: 'currency',
131
+ currency: currencyCode,
132
+ }).format(price);
133
+ }
134
+ ```
135
+
136
+ ## Best Practices
137
+
138
+ 1. **Type Mapping**: Map RevenueCat types to domain types
139
+ 2. **Null Safety**: Handle optional properties safely
140
+ 3. **Validation**: Validate RevenueCat data
141
+ 4. **Formatting**: Format prices and dates consistently
142
+ 5. **Constants**: Use constants for identifiers
143
+
144
+ ## Related
145
+
146
+ - [RevenueCat README](../README.md)
147
+ - [Subscription Manager](../infrastructure/managers/README.md)