@umituz/react-native-subscription 2.14.97 → 2.14.99

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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +461 -0
  3. package/package.json +1 -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/README.md +240 -0
  12. package/src/domains/config/README.md +390 -0
  13. package/src/domains/config/domain/README.md +390 -0
  14. package/src/domains/config/domain/entities/README.md +350 -0
  15. package/src/domains/paywall/README.md +371 -0
  16. package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
  17. package/src/domains/paywall/components/README.md +185 -0
  18. package/src/domains/paywall/entities/README.md +199 -0
  19. package/src/domains/paywall/hooks/README.md +129 -0
  20. package/src/domains/wallet/README.md +292 -0
  21. package/src/domains/wallet/domain/README.md +108 -0
  22. package/src/domains/wallet/domain/entities/README.md +122 -0
  23. package/src/domains/wallet/domain/errors/README.md +157 -0
  24. package/src/domains/wallet/infrastructure/README.md +96 -0
  25. package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
  26. package/src/domains/wallet/presentation/components/README.md +231 -0
  27. package/src/domains/wallet/presentation/hooks/README.md +255 -0
  28. package/src/infrastructure/README.md +514 -0
  29. package/src/infrastructure/mappers/README.md +34 -0
  30. package/src/infrastructure/models/README.md +26 -0
  31. package/src/infrastructure/repositories/README.md +385 -0
  32. package/src/infrastructure/services/README.md +374 -0
  33. package/src/presentation/README.md +410 -0
  34. package/src/presentation/components/README.md +183 -0
  35. package/src/presentation/components/details/CreditRow.md +337 -0
  36. package/src/presentation/components/details/DetailRow.md +283 -0
  37. package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
  38. package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
  39. package/src/presentation/components/details/README.md +449 -0
  40. package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
  41. package/src/presentation/components/feedback/README.md +447 -0
  42. package/src/presentation/components/paywall/PaywallModal.md +444 -0
  43. package/src/presentation/components/paywall/README.md +190 -0
  44. package/src/presentation/components/sections/README.md +468 -0
  45. package/src/presentation/components/sections/SubscriptionSection.md +246 -0
  46. package/src/presentation/hooks/README.md +743 -0
  47. package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
  48. package/src/presentation/hooks/useAuthGate.md +403 -0
  49. package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
  50. package/src/presentation/hooks/useCreditChecker.md +407 -0
  51. package/src/presentation/hooks/useCredits.md +342 -0
  52. package/src/presentation/hooks/useCreditsGate.md +346 -0
  53. package/src/presentation/hooks/useDeductCredit.md +176 -0
  54. package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
  55. package/src/presentation/hooks/useFeatureGate.md +157 -0
  56. package/src/presentation/hooks/useInitializeCredits.md +458 -0
  57. package/src/presentation/hooks/usePaywall.md +334 -0
  58. package/src/presentation/hooks/usePaywallOperations.md +486 -0
  59. package/src/presentation/hooks/usePaywallVisibility.md +344 -0
  60. package/src/presentation/hooks/usePremium.md +230 -0
  61. package/src/presentation/hooks/usePremiumGate.md +423 -0
  62. package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
  63. package/src/presentation/hooks/useSubscription.md +450 -0
  64. package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
  65. package/src/presentation/hooks/useSubscriptionGate.md +168 -0
  66. package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
  67. package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
  68. package/src/presentation/hooks/useUserTier.md +356 -0
  69. package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
  70. package/src/presentation/screens/README.md +194 -0
  71. package/src/presentation/types/README.md +38 -0
  72. package/src/presentation/utils/README.md +52 -0
  73. package/src/revenuecat/README.md +523 -0
  74. package/src/revenuecat/application/README.md +158 -0
  75. package/src/revenuecat/application/ports/README.md +169 -0
  76. package/src/revenuecat/domain/README.md +147 -0
  77. package/src/revenuecat/domain/constants/README.md +183 -0
  78. package/src/revenuecat/domain/entities/README.md +382 -0
  79. package/src/revenuecat/domain/errors/README.md +197 -0
  80. package/src/revenuecat/domain/types/README.md +373 -0
  81. package/src/revenuecat/domain/value-objects/README.md +441 -0
  82. package/src/revenuecat/infrastructure/README.md +50 -0
  83. package/src/revenuecat/infrastructure/config/README.md +40 -0
  84. package/src/revenuecat/infrastructure/handlers/README.md +218 -0
  85. package/src/revenuecat/infrastructure/managers/README.md +49 -0
  86. package/src/revenuecat/infrastructure/services/README.md +325 -0
  87. package/src/revenuecat/infrastructure/utils/README.md +382 -0
  88. package/src/revenuecat/presentation/README.md +184 -0
  89. package/src/revenuecat/presentation/hooks/README.md +56 -0
  90. package/src/utils/README.md +529 -0
@@ -0,0 +1,385 @@
1
+ # Infrastructure Repositories
2
+
3
+ Repository implementations for data persistence.
4
+
5
+ ## Purpose
6
+
7
+ Repositories handle data access and persistence, abstracting away the details of storage mechanisms.
8
+
9
+ ## Available Repositories
10
+
11
+ ### CreditsRepository
12
+
13
+ Manages credits data in Firestore.
14
+
15
+ ```typescript
16
+ import {
17
+ configureCreditsRepository,
18
+ getCreditsRepository,
19
+ type CreditsRepository,
20
+ } from '@umituz/react-native-subscription/infrastructure';
21
+
22
+ // Configure
23
+ configureCreditsRepository({
24
+ firebase: { firestore: db },
25
+ config: creditsConfig,
26
+ });
27
+
28
+ // Get instance
29
+ const repository = getCreditsRepository();
30
+
31
+ // Use
32
+ const credits = await repository.getCredits('user-123');
33
+ ```
34
+
35
+ ### TransactionRepository
36
+
37
+ Manages transaction history.
38
+
39
+ ```typescript
40
+ import {
41
+ createTransactionRepository,
42
+ type TransactionRepository,
43
+ } from '@umituz/react-native-subscription/wallet';
44
+
45
+ const repository = createTransactionRepository({
46
+ firebase: { firestore: db },
47
+ userId: 'user-123',
48
+ });
49
+
50
+ const transactions = await repository.getTransactions({ limit: 20 });
51
+ ```
52
+
53
+ ## Custom Repositories
54
+
55
+ ### Creating a Custom Repository
56
+
57
+ ```typescript
58
+ import type { ISubscriptionRepository } from '@umituz/react-native-subscription/application';
59
+
60
+ class HttpSubscriptionRepository implements ISubscriptionRepository {
61
+ private baseUrl: string;
62
+
63
+ constructor(baseUrl: string) {
64
+ this.baseUrl = baseUrl;
65
+ }
66
+
67
+ async getSubscriptionStatus(userId: string): Promise<SubscriptionStatus | null> {
68
+ const response = await fetch(`${this.baseUrl}/subscriptions/${userId}`);
69
+
70
+ if (!response.ok) {
71
+ throw new SubscriptionRepositoryError('Failed to fetch subscription');
72
+ }
73
+
74
+ return await response.json();
75
+ }
76
+
77
+ async saveSubscriptionStatus(
78
+ userId: string,
79
+ status: SubscriptionStatus
80
+ ): Promise<void> {
81
+ const response = await fetch(`${this.baseUrl}/subscriptions/${userId}`, {
82
+ method: 'PUT',
83
+ headers: { 'Content-Type': 'application/json' },
84
+ body: JSON.stringify(status),
85
+ });
86
+
87
+ if (!response.ok) {
88
+ throw new SubscriptionRepositoryError('Failed to save subscription');
89
+ }
90
+ }
91
+
92
+ async deleteSubscriptionStatus(userId: string): Promise<void> {
93
+ const response = await fetch(`${this.baseUrl}/subscriptions/${userId}`, {
94
+ method: 'DELETE',
95
+ });
96
+
97
+ if (!response.ok) {
98
+ throw new SubscriptionRepositoryError('Failed to delete subscription');
99
+ }
100
+ }
101
+
102
+ isSubscriptionValid(status: SubscriptionStatus): boolean {
103
+ return status.isActive && !isExpired(status.expirationDate);
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### In-Memory Repository (for testing)
109
+
110
+ ```typescript
111
+ class InMemorySubscriptionRepository implements ISubscriptionRepository {
112
+ private storage = new Map<string, SubscriptionStatus>();
113
+
114
+ async getSubscriptionStatus(userId: string): Promise<SubscriptionStatus | null> {
115
+ return this.storage.get(userId) || null;
116
+ }
117
+
118
+ async saveSubscriptionStatus(
119
+ userId: string,
120
+ status: SubscriptionStatus
121
+ ): Promise<void> {
122
+ this.storage.set(userId, status);
123
+ }
124
+
125
+ async deleteSubscriptionStatus(userId: string): Promise<void> {
126
+ this.storage.delete(userId);
127
+ }
128
+
129
+ isSubscriptionValid(status: SubscriptionStatus): boolean {
130
+ return status.isActive && !isExpired(status.expirationDate);
131
+ }
132
+
133
+ // Test helpers
134
+ __reset() {
135
+ this.storage.clear();
136
+ }
137
+ }
138
+ ```
139
+
140
+ ### Redis Repository
141
+
142
+ ```typescript
143
+ import Redis from 'ioredis';
144
+
145
+ class RedisCreditsRepository {
146
+ private redis: Redis;
147
+ private prefix = 'credits:';
148
+
149
+ constructor(redis: Redis) {
150
+ this.redis = redis;
151
+ }
152
+
153
+ async getCredits(userId: string): Promise<UserCredits> {
154
+ const key = `${this.prefix}${userId}`;
155
+ const data = await this.redis.get(key);
156
+
157
+ if (!data) {
158
+ return {
159
+ balance: 0,
160
+ lastUpdated: new Date().toISOString(),
161
+ };
162
+ }
163
+
164
+ return JSON.parse(data);
165
+ }
166
+
167
+ async setCredits(userId: string, credits: UserCredits): Promise<void> {
168
+ const key = `${this.prefix}${userId}`;
169
+ await this.redis.set(key, JSON.stringify(credits));
170
+ }
171
+
172
+ async addCredits(
173
+ userId: string,
174
+ amount: number
175
+ ): Promise<UserCredits> {
176
+ const current = await this.getCredits(userId);
177
+ const updated = {
178
+ ...current,
179
+ balance: current.balance + amount,
180
+ lastUpdated: new Date().toISOString(),
181
+ };
182
+
183
+ await this.setCredits(userId, updated);
184
+ return updated;
185
+ }
186
+ }
187
+ ```
188
+
189
+ ## Repository Patterns
190
+
191
+ ### 1. Active Record Pattern
192
+
193
+ ```typescript
194
+ class Subscription {
195
+ constructor(private data: SubscriptionData) {}
196
+
197
+ async save(): Promise<void> {
198
+ await db.collection('subscriptions').doc(this.data.id).set(this.data);
199
+ }
200
+
201
+ async delete(): Promise<void> {
202
+ await db.collection('subscriptions').doc(this.data.id).delete();
203
+ }
204
+
205
+ static async find(id: string): Promise<Subscription | null> {
206
+ const doc = await db.collection('subscriptions').doc(id).get();
207
+ if (!doc.exists) return null;
208
+ return new Subscription(doc.data());
209
+ }
210
+ }
211
+ ```
212
+
213
+ ### 2. Data Mapper Pattern
214
+
215
+ ```typescript
216
+ class SubscriptionMapper {
217
+ toEntity(doc: FirebaseFirestore.DocumentSnapshot): Subscription {
218
+ const data = doc.data();
219
+ return Subscription.create({
220
+ id: doc.id,
221
+ ...data,
222
+ });
223
+ }
224
+
225
+ toData(entity: Subscription): Record<string, any> {
226
+ return {
227
+ type: entity.type,
228
+ isActive: entity.isActive,
229
+ isPremium: entity.isPremium,
230
+ expirationDate: entity.expirationDate,
231
+ willRenew: entity.willRenew,
232
+ };
233
+ }
234
+ }
235
+ ```
236
+
237
+ ### 3. Repository with Caching
238
+
239
+ ```typescript
240
+ class CachedSubscriptionRepository {
241
+ private cache = new Map<string, { data: SubscriptionStatus; expiry: number }>();
242
+ private ttl = 5 * 60 * 1000; // 5 minutes
243
+
244
+ constructor(private repository: ISubscriptionRepository) {}
245
+
246
+ async getSubscriptionStatus(userId: string): Promise<SubscriptionStatus | null> {
247
+ // Check cache
248
+ const cached = this.cache.get(userId);
249
+ if (cached && cached.expiry > Date.now()) {
250
+ return cached.data;
251
+ }
252
+
253
+ // Fetch from source
254
+ const status = await this.repository.getSubscriptionStatus(userId);
255
+
256
+ // Update cache
257
+ if (status) {
258
+ this.cache.set(userId, {
259
+ data: status,
260
+ expiry: Date.now() + this.ttl,
261
+ });
262
+ }
263
+
264
+ return status;
265
+ }
266
+
267
+ invalidate(userId: string): void {
268
+ this.cache.delete(userId);
269
+ }
270
+
271
+ invalidateAll(): void {
272
+ this.cache.clear();
273
+ }
274
+ }
275
+ ```
276
+
277
+ ## Transaction Support
278
+
279
+ ### Firestore Transactions
280
+
281
+ ```typescript
282
+ class TransactionalCreditsRepository {
283
+ async transferCredits(
284
+ fromUserId: string,
285
+ toUserId: string,
286
+ amount: number
287
+ ): Promise<void> {
288
+ await db.runTransaction(async (transaction) => {
289
+ const fromRef = db.collection('credits').doc(fromUserId);
290
+ const toRef = db.collection('credits').doc(toUserId);
291
+
292
+ const fromDoc = await transaction.get(fromRef);
293
+ const toDoc = await transaction.get(toRef);
294
+
295
+ const fromBalance = fromDoc.data()?.balance || 0;
296
+ const toBalance = toDoc.data()?.balance || 0;
297
+
298
+ if (fromBalance < amount) {
299
+ throw new InsufficientCreditsError('Insufficient credits');
300
+ }
301
+
302
+ transaction.update(fromRef, { balance: fromBalance - amount });
303
+ transaction.update(toRef, { balance: toBalance + amount });
304
+ });
305
+ }
306
+ }
307
+ ```
308
+
309
+ ## Real-Time Updates
310
+
311
+ ### Firestore Realtime Listener
312
+
313
+ ```typescript
314
+ class RealtimeSubscriptionRepository {
315
+ subscribeToStatus(
316
+ userId: string,
317
+ callback: (status: SubscriptionStatus) => void
318
+ ): () => void {
319
+ const unsubscribe = db
320
+ .collection('subscriptions')
321
+ .doc(userId)
322
+ .onSnapshot((doc) => {
323
+ if (doc.exists) {
324
+ callback(doc.data() as SubscriptionStatus);
325
+ }
326
+ });
327
+
328
+ return unsubscribe;
329
+ }
330
+ }
331
+ ```
332
+
333
+ ## Testing Repositories
334
+
335
+ ### Mock Repository Factory
336
+
337
+ ```typescript
338
+ function createMockRepository(options?: {
339
+ initialData?: Map<string, SubscriptionStatus>;
340
+ latency?: number;
341
+ }): ISubscriptionRepository {
342
+ const data = options?.initialData || new Map();
343
+ const latency = options?.latency || 0;
344
+
345
+ return {
346
+ async getSubscriptionStatus(userId: string) {
347
+ if (latency > 0) {
348
+ await sleep(latency);
349
+ }
350
+ return data.get(userId) || null;
351
+ },
352
+
353
+ async saveSubscriptionStatus(userId: string, status: SubscriptionStatus) {
354
+ if (latency > 0) {
355
+ await sleep(latency);
356
+ }
357
+ data.set(userId, status);
358
+ },
359
+
360
+ async deleteSubscriptionStatus(userId: string) {
361
+ data.delete(userId);
362
+ },
363
+
364
+ isSubscriptionValid(status: SubscriptionStatus) {
365
+ return status.isActive && !isExpired(status.expirationDate);
366
+ },
367
+ };
368
+ }
369
+ ```
370
+
371
+ ## Best Practices
372
+
373
+ 1. **Interface Segregation** - Keep interfaces focused
374
+ 2. **Error Handling** - Transform storage errors to domain errors
375
+ 3. **Logging** - Log repository operations
376
+ 4. **Validation** - Validate data before saving
377
+ 5. **Performance** - Use caching and batching
378
+ 6. **Testing** - Mock repositories for unit tests
379
+ 7. **Transactions** - Use transactions for multi-document updates
380
+
381
+ ## Related
382
+
383
+ - [Infrastructure Layer](../../README.md)
384
+ - [Infrastructure Services](../services/README.md)
385
+ - [Application Ports](../../application/ports/README.md)