@umituz/react-native-subscription 2.14.47 → 2.14.49

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 (32) hide show
  1. package/package.json +3 -3
  2. package/src/domains/paywall/components/PaywallHeader.tsx +1 -0
  3. package/src/domains/paywall/components/PaywallModal.styles.ts +49 -0
  4. package/src/domains/paywall/components/PaywallModal.tsx +2 -37
  5. package/src/domains/wallet/domain/entities/CreditCost.ts +3 -3
  6. package/src/domains/wallet/infrastructure/repositories/TransactionRepository.ts +11 -20
  7. package/src/domains/wallet/presentation/components/BalanceCard.tsx +4 -3
  8. package/src/domains/wallet/presentation/components/TransactionItem.tsx +4 -3
  9. package/src/domains/wallet/presentation/components/TransactionList.tsx +7 -5
  10. package/src/domains/wallet/presentation/hooks/useWallet.ts +6 -4
  11. package/src/domains/wallet/presentation/screens/WalletScreen.tsx +11 -8
  12. package/src/infrastructure/repositories/CreditsRepository.ts +7 -42
  13. package/src/infrastructure/services/CreditsInitializer.ts +1 -52
  14. package/src/presentation/components/feedback/PaywallFeedbackModal.tsx +1 -0
  15. package/src/presentation/components/sections/SubscriptionSection.tsx +4 -3
  16. package/src/presentation/hooks/useCreditChecker.ts +3 -2
  17. package/src/presentation/hooks/useCredits.ts +4 -3
  18. package/src/presentation/hooks/usePremium.ts +4 -3
  19. package/src/presentation/hooks/useSubscriptionDetails.ts +3 -2
  20. package/src/presentation/hooks/useSubscriptionSettingsConfig.ts +4 -3
  21. package/src/presentation/screens/SubscriptionDetailScreen.tsx +3 -2
  22. package/src/presentation/screens/components/UpgradePrompt.tsx +4 -3
  23. package/src/revenuecat/infrastructure/services/CustomerInfoListenerManager.ts +60 -158
  24. package/src/revenuecat/infrastructure/services/OfferingsFetcher.ts +13 -29
  25. package/src/revenuecat/infrastructure/services/PurchaseHandler.ts +64 -88
  26. package/src/revenuecat/infrastructure/services/RestoreHandler.ts +32 -48
  27. package/src/revenuecat/infrastructure/services/RevenueCatInitializer.ts +90 -219
  28. package/src/revenuecat/infrastructure/services/RevenueCatService.ts +121 -126
  29. package/src/revenuecat/infrastructure/utils/InitializationCache.ts +25 -29
  30. package/src/revenuecat/infrastructure/utils/PremiumStatusSyncer.ts +52 -100
  31. package/src/revenuecat/infrastructure/utils/UserIdProvider.ts +17 -25
  32. package/src/revenuecat/presentation/hooks/usePaywallFlow.ts +9 -8
@@ -3,41 +3,37 @@
3
3
  * Manages promise caching and user state for initialization
4
4
  */
5
5
 
6
-
7
6
  export class InitializationCache {
8
- private initPromise: Promise<boolean> | null = null;
9
- private currentUserId: string | null = null;
7
+ private initPromise: Promise<boolean> | null = null;
8
+ private currentUserId: string | null = null;
10
9
 
11
- shouldReinitialize(userId: string): boolean {
12
- if (!this.initPromise) {
13
- return true;
14
- }
10
+ shouldReinitialize(userId: string): boolean {
11
+ if (!this.initPromise) {
12
+ return true;
13
+ }
15
14
 
16
- if (this.currentUserId !== userId) {
17
- oldUserId: this.currentUserId,
18
- newUserId: userId,
19
- });
20
- return true;
21
- }
15
+ if (this.currentUserId !== userId) {
16
+ return true;
17
+ }
22
18
 
23
- return false;
24
- }
19
+ return false;
20
+ }
25
21
 
26
- getExistingPromise(): Promise<boolean> | null {
27
- return this.initPromise;
28
- }
22
+ getExistingPromise(): Promise<boolean> | null {
23
+ return this.initPromise;
24
+ }
29
25
 
30
- setPromise(promise: Promise<boolean>, userId: string): void {
31
- this.initPromise = promise;
32
- this.currentUserId = userId;
33
- }
26
+ setPromise(promise: Promise<boolean>, userId: string): void {
27
+ this.initPromise = promise;
28
+ this.currentUserId = userId;
29
+ }
34
30
 
35
- getCurrentUserId(): string | null {
36
- return this.currentUserId;
37
- }
31
+ getCurrentUserId(): string | null {
32
+ return this.currentUserId;
33
+ }
38
34
 
39
- reset(): void {
40
- this.initPromise = null;
41
- this.currentUserId = null;
42
- }
35
+ reset(): void {
36
+ this.initPromise = null;
37
+ this.currentUserId = null;
38
+ }
43
39
  }
@@ -4,121 +4,73 @@
4
4
  */
5
5
 
6
6
  import type { CustomerInfo } from "react-native-purchases";
7
- import type { RevenueCatConfig } from '../../domain/value-objects/RevenueCatConfig';
8
- import { getPremiumEntitlement } from '../../domain/types/RevenueCatTypes';
7
+ import type { RevenueCatConfig } from "../../domain/value-objects/RevenueCatConfig";
8
+ import { getPremiumEntitlement } from "../../domain/types/RevenueCatTypes";
9
9
  import { getExpirationDate } from "./ExpirationDateCalculator";
10
10
 
11
11
  export async function syncPremiumStatus(
12
- config: RevenueCatConfig,
13
- userId: string,
14
- customerInfo: CustomerInfo
12
+ config: RevenueCatConfig,
13
+ userId: string,
14
+ customerInfo: CustomerInfo
15
15
  ): Promise<void> {
16
- if (!config.onPremiumStatusChanged) {
17
- return;
18
- }
19
-
20
- const entitlementIdentifier = config.entitlementIdentifier;
21
- const premiumEntitlement = getPremiumEntitlement(
22
- customerInfo,
23
- entitlementIdentifier
24
- );
25
-
26
- const isPremium = !!premiumEntitlement;
27
-
28
- userId,
29
- isPremium,
30
- productId: premiumEntitlement?.productIdentifier,
31
- });
32
-
33
- try {
34
- if (premiumEntitlement) {
35
- const productId = premiumEntitlement.productIdentifier;
36
- const expiresAt = getExpirationDate(premiumEntitlement);
37
- await config.onPremiumStatusChanged(
38
- userId,
39
- true,
40
- productId,
41
- expiresAt || undefined
42
- );
43
- } else {
44
- await config.onPremiumStatusChanged(userId, false);
16
+ if (!config.onPremiumStatusChanged) {
17
+ return;
45
18
  }
46
19
 
47
- userId,
48
- isPremium,
49
- });
50
- } catch (error) {
51
- error instanceof Error ? error : new Error(String(error)),
52
- {
53
- packageName: "subscription",
54
- operation: "sync_premium_status",
55
- userId,
56
- isPremium,
57
- }
20
+ const entitlementIdentifier = config.entitlementIdentifier;
21
+ const premiumEntitlement = getPremiumEntitlement(
22
+ customerInfo,
23
+ entitlementIdentifier
58
24
  );
59
- }
25
+
26
+ try {
27
+ if (premiumEntitlement) {
28
+ const productId = premiumEntitlement.productIdentifier;
29
+ const expiresAt = getExpirationDate(premiumEntitlement);
30
+ await config.onPremiumStatusChanged(
31
+ userId,
32
+ true,
33
+ productId,
34
+ expiresAt || undefined
35
+ );
36
+ } else {
37
+ await config.onPremiumStatusChanged(userId, false);
38
+ }
39
+ } catch {
40
+ // Silent error handling
41
+ }
60
42
  }
61
43
 
62
44
  export async function notifyPurchaseCompleted(
63
- config: RevenueCatConfig,
64
- userId: string,
65
- productId: string,
66
- customerInfo: CustomerInfo
45
+ config: RevenueCatConfig,
46
+ userId: string,
47
+ productId: string,
48
+ customerInfo: CustomerInfo
67
49
  ): Promise<void> {
68
- if (!config.onPurchaseCompleted) {
69
- return;
70
- }
71
-
72
- userId,
73
- productId,
74
- });
75
-
76
- try {
77
- await config.onPurchaseCompleted(userId, productId, customerInfo);
50
+ if (!config.onPurchaseCompleted) {
51
+ return;
52
+ }
78
53
 
79
- userId,
80
- productId,
81
- });
82
- } catch (error) {
83
- error instanceof Error ? error : new Error(String(error)),
84
- {
85
- packageName: "subscription",
86
- operation: "purchase_callback",
87
- userId,
88
- productId,
89
- }
90
- );
91
- }
54
+ try {
55
+ await config.onPurchaseCompleted(userId, productId, customerInfo);
56
+ } catch {
57
+ // Silent error handling
58
+ }
92
59
  }
93
60
 
94
61
  export async function notifyRestoreCompleted(
95
- config: RevenueCatConfig,
96
- userId: string,
97
- isPremium: boolean,
98
- customerInfo: CustomerInfo
62
+ config: RevenueCatConfig,
63
+ userId: string,
64
+ isPremium: boolean,
65
+ customerInfo: CustomerInfo
99
66
  ): Promise<void> {
100
- if (!config.onRestoreCompleted) {
101
- return;
102
- }
103
-
104
- userId,
105
- isPremium,
106
- });
107
-
108
- try {
109
- await config.onRestoreCompleted(userId, isPremium, customerInfo);
67
+ if (!config.onRestoreCompleted) {
68
+ return;
69
+ }
110
70
 
111
- userId,
112
- isPremium,
113
- });
114
- } catch (error) {
115
- error instanceof Error ? error : new Error(String(error)),
116
- {
117
- packageName: "subscription",
118
- operation: "restore_callback",
119
- userId,
120
- isPremium,
121
- }
122
- );
123
- }
71
+ try {
72
+ await config.onRestoreCompleted(userId, isPremium, customerInfo);
73
+ } catch {
74
+ // Silent error handling
75
+ }
124
76
  }
@@ -3,36 +3,28 @@
3
3
  * Manages user ID retrieval (anonymous or authenticated)
4
4
  */
5
5
 
6
-
7
6
  export class UserIdProvider {
8
- private cachedAnonUserId: string | null = null;
9
- private getAnonymousUserIdFn: (() => Promise<string>) | null = null;
10
-
11
- configure(getAnonymousUserId: () => Promise<string>): void {
12
- this.getAnonymousUserIdFn = getAnonymousUserId;
13
- }
7
+ private cachedAnonUserId: string | null = null;
8
+ private getAnonymousUserIdFn: (() => Promise<string>) | null = null;
14
9
 
15
- async getOrCreateAnonymousUserId(): Promise<string> {
16
- if (this.cachedAnonUserId) {
17
- return this.cachedAnonUserId;
10
+ configure(getAnonymousUserId: () => Promise<string>): void {
11
+ this.getAnonymousUserIdFn = getAnonymousUserId;
18
12
  }
19
13
 
20
- if (!this.getAnonymousUserIdFn) {
21
- const error = new Error("Anonymous user ID provider not configured");
22
- packageName: "subscription",
23
- operation: "get_anon_user_id",
24
- });
25
- throw error;
26
- }
14
+ async getOrCreateAnonymousUserId(): Promise<string> {
15
+ if (this.cachedAnonUserId) {
16
+ return this.cachedAnonUserId;
17
+ }
27
18
 
28
- this.cachedAnonUserId = await this.getAnonymousUserIdFn();
29
- userId: this.cachedAnonUserId,
30
- });
19
+ if (!this.getAnonymousUserIdFn) {
20
+ throw new Error("Anonymous user ID provider not configured");
21
+ }
31
22
 
32
- return this.cachedAnonUserId;
33
- }
23
+ this.cachedAnonUserId = await this.getAnonymousUserIdFn();
24
+ return this.cachedAnonUserId;
25
+ }
34
26
 
35
- reset(): void {
36
- this.cachedAnonUserId = null;
37
- }
27
+ reset(): void {
28
+ this.cachedAnonUserId = null;
29
+ }
38
30
  }
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useEffect, useCallback } from 'react';
7
- import AsyncStorage from '@react-native-async-storage/async-storage';
7
+ import { useStorage } from '@umituz/react-native-storage';
8
8
 
9
9
  const PAYWALL_SHOWN_KEY = 'post_onboarding_paywall_shown';
10
10
 
@@ -23,33 +23,34 @@ export interface UsePaywallFlowResult {
23
23
 
24
24
  export const usePaywallFlow = (options: UsePaywallFlowOptions = {}): UsePaywallFlowResult => {
25
25
  const { showAfterOnboarding = false } = options;
26
+ const { getString, setString } = useStorage();
26
27
  const [showPostOnboardingPaywall, setShowPostOnboardingPaywall] = useState(showAfterOnboarding);
27
28
  const [paywallShown, setPaywallShown] = useState(false);
28
29
 
29
30
  // Load persisted state
30
31
  useEffect(() => {
31
32
  const loadPersistedState = async () => {
32
- const value = await AsyncStorage.getItem(PAYWALL_SHOWN_KEY);
33
+ const value = await getString(PAYWALL_SHOWN_KEY, '');
33
34
  setPaywallShown(value === 'true');
34
35
  };
35
36
 
36
37
  loadPersistedState();
37
- }, []);
38
+ }, [getString]);
38
39
 
39
- const closePostOnboardingPaywall = useCallback(async (isPremium: boolean) => {
40
- await AsyncStorage.setItem(PAYWALL_SHOWN_KEY, 'true');
40
+ const closePostOnboardingPaywall = useCallback(async (_isPremium: boolean) => {
41
+ await setString(PAYWALL_SHOWN_KEY, 'true');
41
42
  setShowPostOnboardingPaywall(false);
42
43
  setPaywallShown(true);
43
- }, []);
44
+ }, [setString]);
44
45
 
45
46
  const hidePostOnboardingPaywall = useCallback(() => {
46
47
  setShowPostOnboardingPaywall(false);
47
48
  }, []);
48
49
 
49
50
  const markPaywallShown = useCallback(async () => {
50
- await AsyncStorage.setItem(PAYWALL_SHOWN_KEY, 'true');
51
+ await setString(PAYWALL_SHOWN_KEY, 'true');
51
52
  setPaywallShown(true);
52
- }, []);
53
+ }, [setString]);
53
54
 
54
55
  return {
55
56
  showPostOnboardingPaywall,