@umituz/react-native-subscription 2.14.44 → 2.14.45
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 +1 -1
- package/src/domain/entities/SubscriptionStatus.test.ts +0 -1
- package/src/domains/paywall/components/PaywallHeader.tsx +0 -1
- package/src/domains/wallet/domain/entities/CreditCost.ts +0 -1
- package/src/domains/wallet/infrastructure/repositories/TransactionRepository.ts +0 -1
- package/src/domains/wallet/presentation/components/BalanceCard.tsx +0 -1
- package/src/domains/wallet/presentation/components/TransactionItem.tsx +0 -1
- package/src/domains/wallet/presentation/components/TransactionList.tsx +0 -2
- package/src/domains/wallet/presentation/hooks/useWallet.ts +0 -2
- package/src/domains/wallet/presentation/screens/WalletScreen.tsx +0 -3
- package/src/index.ts +1 -0
- package/src/infrastructure/repositories/CreditsRepository.ts +0 -1
- package/src/infrastructure/services/CreditsInitializer.ts +0 -1
- package/src/infrastructure/services/SubscriptionService.ts +0 -2
- package/src/presentation/components/feedback/PaywallFeedbackModal.tsx +0 -1
- package/src/presentation/components/sections/SubscriptionSection.tsx +0 -1
- package/src/presentation/hooks/useCreditChecker.ts +0 -1
- package/src/presentation/hooks/useCredits.ts +0 -1
- package/src/presentation/hooks/usePremium.ts +0 -1
- package/src/presentation/hooks/useSubscriptionDetails.ts +0 -1
- package/src/presentation/hooks/useSubscriptionSettingsConfig.ts +0 -1
- package/src/presentation/screens/SubscriptionDetailScreen.tsx +0 -1
- package/src/presentation/screens/components/UpgradePrompt.tsx +0 -1
- package/src/revenuecat/infrastructure/handlers/PackageHandler.ts +17 -19
- package/src/revenuecat/infrastructure/managers/SubscriptionManager.ts +17 -10
- package/src/revenuecat/infrastructure/services/OfferingsFetcher.ts +0 -1
- package/src/revenuecat/infrastructure/services/PurchaseHandler.ts +0 -4
- package/src/revenuecat/infrastructure/services/RestoreHandler.ts +0 -3
- package/src/revenuecat/infrastructure/services/RevenueCatInitializer.ts +0 -1
- package/src/revenuecat/infrastructure/services/RevenueCatService.ts +0 -1
- package/src/revenuecat/infrastructure/utils/PremiumStatusSyncer.ts +0 -1
- package/src/revenuecat/infrastructure/utils/UserIdProvider.ts +0 -1
- package/src/revenuecat/presentation/hooks/useCustomerInfo.ts +16 -12
- package/src/revenuecat/presentation/hooks/useInitializeSubscription.ts +11 -13
- package/src/revenuecat/presentation/hooks/usePaywallFlow.ts +62 -0
- package/src/revenuecat/presentation/hooks/usePurchasePackage.ts +25 -18
- package/src/revenuecat/presentation/hooks/useRestorePurchase.ts +17 -14
- package/src/revenuecat/presentation/hooks/useSubscriptionPackages.ts +0 -7
- package/src/utils/__tests__/authUtils.test.ts +0 -1
- package/src/utils/__tests__/dateValidationUtils.test.ts +0 -1
- package/src/utils/__tests__/edgeCases.test.ts +0 -2
- package/src/utils/__tests__/premiumUtils.test.ts +0 -2
- package/src/utils/__tests__/tierUtils.test.ts +0 -2
- package/src/utils/__tests__/validation.test.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.45",
|
|
4
4
|
"description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -7,13 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
import React from "react";
|
|
9
9
|
import { View, StyleSheet, ScrollView, ActivityIndicator } from "react-native";
|
|
10
|
-
import {
|
|
11
10
|
useAppDesignTokens,
|
|
12
11
|
AtomicText,
|
|
13
12
|
AtomicIcon,
|
|
14
13
|
} from "@umituz/react-native-design-system";
|
|
15
14
|
import type { CreditLog } from "../../domain/types/transaction.types";
|
|
16
|
-
import {
|
|
17
15
|
TransactionItem,
|
|
18
16
|
type TransactionItemTranslations,
|
|
19
17
|
} from "./TransactionItem";
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { useCallback, useMemo } from "react";
|
|
9
|
-
import {
|
|
10
9
|
useCredits,
|
|
11
10
|
type UseCreditsParams,
|
|
12
11
|
} from "../../../../presentation/hooks/useCredits";
|
|
13
|
-
import {
|
|
14
12
|
useTransactionHistory,
|
|
15
13
|
type UseTransactionHistoryParams,
|
|
16
14
|
} from "./useTransactionHistory";
|
|
@@ -9,17 +9,14 @@
|
|
|
9
9
|
import React from "react";
|
|
10
10
|
import { View, StyleSheet, ActivityIndicator, TouchableOpacity } from "react-native";
|
|
11
11
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
12
|
-
import {
|
|
13
12
|
useAppDesignTokens,
|
|
14
13
|
AtomicText,
|
|
15
14
|
AtomicIcon,
|
|
16
15
|
ScreenLayout,
|
|
17
16
|
} from "@umituz/react-native-design-system";
|
|
18
|
-
import {
|
|
19
17
|
BalanceCard,
|
|
20
18
|
type BalanceCardTranslations,
|
|
21
19
|
} from "../components/BalanceCard";
|
|
22
|
-
import {
|
|
23
20
|
TransactionList,
|
|
24
21
|
type TransactionListTranslations,
|
|
25
22
|
} from "../components/TransactionList";
|
package/src/index.ts
CHANGED
|
@@ -464,3 +464,4 @@ export {
|
|
|
464
464
|
useRestorePurchase,
|
|
465
465
|
SUBSCRIPTION_QUERY_KEYS,
|
|
466
466
|
} from "./revenuecat/presentation/hooks/useSubscriptionQueries";
|
|
467
|
+
export { usePaywallFlow, type UsePaywallFlowOptions, type UsePaywallFlowResult } from './revenuecat/presentation/hooks/usePaywallFlow';
|
|
@@ -7,12 +7,10 @@ import type { ISubscriptionService } from "../../application/ports/ISubscription
|
|
|
7
7
|
import type { ISubscriptionRepository } from "../../application/ports/ISubscriptionRepository";
|
|
8
8
|
import type { SubscriptionStatus } from "../../domain/entities/SubscriptionStatus";
|
|
9
9
|
import { createDefaultSubscriptionStatus } from "../../domain/entities/SubscriptionStatus";
|
|
10
|
-
import {
|
|
11
10
|
SubscriptionRepositoryError,
|
|
12
11
|
SubscriptionValidationError,
|
|
13
12
|
} from "../../domain/errors/SubscriptionError";
|
|
14
13
|
import type { SubscriptionConfig } from "../../domain/value-objects/SubscriptionConfig";
|
|
15
|
-
import {
|
|
16
14
|
activateSubscription,
|
|
17
15
|
deactivateSubscription,
|
|
18
16
|
type ActivationHandlerConfig,
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import { useMemo } from "react";
|
|
8
8
|
import type { CreditType } from "../../domain/entities/Credits";
|
|
9
9
|
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
10
|
-
import {
|
|
11
10
|
createCreditChecker,
|
|
12
11
|
type CreditCheckResult,
|
|
13
12
|
} from "../../utils/creditChecker";
|
|
@@ -12,7 +12,6 @@ import type { PurchasesPackage } from 'react-native-purchases';
|
|
|
12
12
|
import type { UserCredits } from '../../domain/entities/Credits';
|
|
13
13
|
import { useCredits } from './useCredits';
|
|
14
14
|
import { useSubscriptionStatus } from './useSubscriptionStatus';
|
|
15
|
-
import {
|
|
16
15
|
useSubscriptionPackages,
|
|
17
16
|
usePurchasePackage,
|
|
18
17
|
useRestorePurchase,
|
|
@@ -10,7 +10,6 @@ import { useSubscriptionStatus } from "./useSubscriptionStatus";
|
|
|
10
10
|
import { useCustomerInfo } from "../../revenuecat/presentation/hooks/useCustomerInfo";
|
|
11
11
|
import { usePaywallVisibility } from "./usePaywallVisibility";
|
|
12
12
|
import { SubscriptionManager } from "../../revenuecat/infrastructure/managers/SubscriptionManager";
|
|
13
|
-
import {
|
|
14
13
|
convertPurchasedAt,
|
|
15
14
|
formatDateForLocale,
|
|
16
15
|
calculateDaysRemaining,
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import type { PurchasesPackage, CustomerInfo } from "react-native-purchases";
|
|
7
7
|
import type { IRevenueCatService } from "../../application/ports/IRevenueCatService";
|
|
8
8
|
import { getPremiumEntitlement } from "../../domain/types/RevenueCatTypes";
|
|
9
|
-
import {
|
|
10
9
|
|
|
11
10
|
export interface PremiumStatus {
|
|
12
11
|
isPremium: boolean;
|
|
@@ -49,26 +48,22 @@ export class PackageHandler {
|
|
|
49
48
|
});
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
identifier: offering?.identifier,
|
|
53
|
-
count: offering?.availablePackages?.length ?? 0,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
51
|
return offering?.availablePackages ?? [];
|
|
57
52
|
} catch (error) {
|
|
58
53
|
if (__DEV__) {
|
|
59
54
|
console.error('[DEBUG PackageHandler] fetchOfferings failed:', error);
|
|
60
55
|
}
|
|
61
|
-
packageName: "subscription",
|
|
62
|
-
operation: "fetch_packages",
|
|
63
|
-
});
|
|
64
56
|
return [];
|
|
65
57
|
}
|
|
66
58
|
}
|
|
67
59
|
|
|
68
60
|
async purchase(pkg: PurchasesPackage, userId: string): Promise<boolean> {
|
|
69
61
|
if (!this.service?.isInitialized()) {
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
if (__DEV__) {
|
|
63
|
+
console.log('[DEBUG PackageHandler] Service not initialized', {
|
|
64
|
+
productId: pkg.product.identifier,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
72
67
|
return false;
|
|
73
68
|
}
|
|
74
69
|
|
|
@@ -76,11 +71,12 @@ export class PackageHandler {
|
|
|
76
71
|
const result = await this.service.purchasePackage(pkg, userId);
|
|
77
72
|
return result.success;
|
|
78
73
|
} catch (error) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
if (__DEV__) {
|
|
75
|
+
console.error('[DEBUG PackageHandler] Purchase failed:', {
|
|
76
|
+
error,
|
|
77
|
+
productId: pkg.product.identifier,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
84
80
|
return false;
|
|
85
81
|
}
|
|
86
82
|
}
|
|
@@ -107,10 +103,12 @@ export class PackageHandler {
|
|
|
107
103
|
|
|
108
104
|
return { success: result.success, productId };
|
|
109
105
|
} catch (error) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
if (__DEV__) {
|
|
107
|
+
console.error('[DEBUG PackageHandler] Restore failed:', {
|
|
108
|
+
error,
|
|
109
|
+
userId,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
114
112
|
return { success: false, productId: null };
|
|
115
113
|
}
|
|
116
114
|
}
|
|
@@ -12,7 +12,6 @@ import { UserIdProvider } from "../utils/UserIdProvider";
|
|
|
12
12
|
import { InitializationCache } from "../utils/InitializationCache";
|
|
13
13
|
import { PackageHandler } from "../handlers/PackageHandler";
|
|
14
14
|
import type { PremiumStatus, RestoreResultInfo } from "../handlers/PackageHandler";
|
|
15
|
-
import {
|
|
16
15
|
|
|
17
16
|
export interface SubscriptionManagerConfig {
|
|
18
17
|
config: RevenueCatConfig;
|
|
@@ -35,16 +34,22 @@ class SubscriptionManagerImpl {
|
|
|
35
34
|
this.userIdProvider.configure(config.getAnonymousUserId);
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (__DEV__) {
|
|
38
|
+
console.log('[DEBUG SubscriptionManager] Configured:', {
|
|
39
|
+
entitlementId: config.config.entitlementIdentifier,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
private ensureConfigured(): void {
|
|
43
45
|
if (!this.managerConfig || !this.packageHandler) {
|
|
44
46
|
const error = new Error("SubscriptionManager not configured");
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
if (__DEV__) {
|
|
48
|
+
console.error('[DEBUG SubscriptionManager] Not configured:', {
|
|
49
|
+
hasConfig: !!this.managerConfig,
|
|
50
|
+
hasHandler: !!this.packageHandler,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
48
53
|
throw error;
|
|
49
54
|
}
|
|
50
55
|
}
|
|
@@ -66,10 +71,12 @@ class SubscriptionManagerImpl {
|
|
|
66
71
|
const result = await this.serviceInstance.initialize(userId);
|
|
67
72
|
return result.success;
|
|
68
73
|
} catch (error) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
if (__DEV__) {
|
|
75
|
+
console.error('[DEBUG SubscriptionManager] Initialization failed:', {
|
|
76
|
+
error,
|
|
77
|
+
userId,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
73
80
|
throw error;
|
|
74
81
|
}
|
|
75
82
|
}
|
|
@@ -5,20 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import Purchases, { type PurchasesPackage } from "react-native-purchases";
|
|
7
7
|
import type { PurchaseResult } from '../../application/ports/IRevenueCatService';
|
|
8
|
-
import {
|
|
9
8
|
RevenueCatPurchaseError,
|
|
10
9
|
RevenueCatInitializationError,
|
|
11
10
|
} from '../../domain/errors/RevenueCatError';
|
|
12
11
|
import type { RevenueCatConfig } from '../../domain/value-objects/RevenueCatConfig';
|
|
13
|
-
import {
|
|
14
12
|
isUserCancelledError,
|
|
15
13
|
getErrorMessage,
|
|
16
14
|
} from '../../domain/types/RevenueCatTypes';
|
|
17
|
-
import {
|
|
18
15
|
syncPremiumStatus,
|
|
19
16
|
notifyPurchaseCompleted,
|
|
20
17
|
} from '../utils/PremiumStatusSyncer';
|
|
21
|
-
import {
|
|
22
18
|
|
|
23
19
|
export interface PurchaseHandlerDeps {
|
|
24
20
|
config: RevenueCatConfig;
|
|
@@ -5,17 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
import Purchases from "react-native-purchases";
|
|
7
7
|
import type { RestoreResult } from '../../application/ports/IRevenueCatService';
|
|
8
|
-
import {
|
|
9
8
|
RevenueCatRestoreError,
|
|
10
9
|
RevenueCatInitializationError,
|
|
11
10
|
} from '../../domain/errors/RevenueCatError';
|
|
12
11
|
import type { RevenueCatConfig } from '../../domain/value-objects/RevenueCatConfig';
|
|
13
12
|
import { getErrorMessage } from '../../domain/types/RevenueCatTypes';
|
|
14
|
-
import {
|
|
15
13
|
syncPremiumStatus,
|
|
16
14
|
notifyRestoreCompleted,
|
|
17
15
|
} from '../utils/PremiumStatusSyncer';
|
|
18
|
-
import {
|
|
19
16
|
|
|
20
17
|
export interface RestoreHandlerDeps {
|
|
21
18
|
config: RevenueCatConfig;
|
|
@@ -8,7 +8,6 @@ import type { InitializeResult } from '../../application/ports/IRevenueCatServic
|
|
|
8
8
|
import type { RevenueCatConfig } from '../../domain/value-objects/RevenueCatConfig';
|
|
9
9
|
import { getErrorMessage } from '../../domain/types/RevenueCatTypes';
|
|
10
10
|
import { resolveApiKey } from '../utils/ApiKeyResolver';
|
|
11
|
-
import {
|
|
12
11
|
|
|
13
12
|
export interface InitializerDeps {
|
|
14
13
|
config: RevenueCatConfig;
|
|
@@ -19,7 +19,6 @@ import { handlePurchase } from "./PurchaseHandler";
|
|
|
19
19
|
import { handleRestore } from "./RestoreHandler";
|
|
20
20
|
import { CustomerInfoListenerManager } from "./CustomerInfoListenerManager";
|
|
21
21
|
import { ServiceStateManager } from "./ServiceStateManager";
|
|
22
|
-
import {
|
|
23
22
|
|
|
24
23
|
export class RevenueCatService implements IRevenueCatService {
|
|
25
24
|
private stateManager: ServiceStateManager;
|
|
@@ -7,7 +7,6 @@ import type { CustomerInfo } from "react-native-purchases";
|
|
|
7
7
|
import type { RevenueCatConfig } from '../../domain/value-objects/RevenueCatConfig';
|
|
8
8
|
import { getPremiumEntitlement } from '../../domain/types/RevenueCatTypes';
|
|
9
9
|
import { getExpirationDate } from "./ExpirationDateCalculator";
|
|
10
|
-
import {
|
|
11
10
|
|
|
12
11
|
export async function syncPremiumStatus(
|
|
13
12
|
config: RevenueCatConfig,
|
|
@@ -66,27 +66,28 @@ export function useCustomerInfo(): UseCustomerInfoResult {
|
|
|
66
66
|
setIsFetching(true);
|
|
67
67
|
setError(null);
|
|
68
68
|
|
|
69
|
-
|
|
70
69
|
// SDK returns cached data instantly if available
|
|
71
70
|
// Network fetch happens in background automatically
|
|
72
71
|
const info = await Purchases.getCustomerInfo();
|
|
73
72
|
|
|
74
73
|
setCustomerInfo(info);
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
if (__DEV__) {
|
|
76
|
+
console.log('[DEBUG useCustomerInfo] Fetched:', {
|
|
77
|
+
hasActiveEntitlements: Object.keys(info.entitlements.active).length > 0,
|
|
78
|
+
latestExpiration: info.latestExpirationDate || "none",
|
|
79
|
+
});
|
|
80
|
+
}
|
|
79
81
|
} catch (err) {
|
|
80
82
|
const errorMessage =
|
|
81
83
|
err instanceof Error ? err.message : "Failed to fetch customer info";
|
|
82
84
|
setError(errorMessage);
|
|
83
85
|
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
86
|
+
if (__DEV__) {
|
|
87
|
+
console.error('[DEBUG useCustomerInfo] Error:', {
|
|
88
|
+
error: err,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
90
91
|
} finally {
|
|
91
92
|
setLoading(false);
|
|
92
93
|
setIsFetching(false);
|
|
@@ -99,8 +100,11 @@ export function useCustomerInfo(): UseCustomerInfoResult {
|
|
|
99
100
|
|
|
100
101
|
// Listen for real-time updates (renewals, purchases, restore)
|
|
101
102
|
const listener = (info: CustomerInfo) => {
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
if (__DEV__) {
|
|
104
|
+
console.log('[DEBUG useCustomerInfo] Listener update:', {
|
|
105
|
+
hasActiveEntitlements: Object.keys(info.entitlements.active).length > 0,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
104
108
|
|
|
105
109
|
setCustomerInfo(info);
|
|
106
110
|
setError(null);
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
7
7
|
import { SubscriptionManager } from '../../infrastructure/managers/SubscriptionManager';
|
|
8
|
-
import {
|
|
9
8
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -20,8 +19,9 @@ export const useInitializeSubscription = (userId: string | undefined) => {
|
|
|
20
19
|
throw new Error("User not authenticated");
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
if (__DEV__) {
|
|
23
|
+
console.log('[DEBUG useInitializeSubscription] Initializing:', { userId });
|
|
24
|
+
}
|
|
25
25
|
|
|
26
26
|
return SubscriptionManager.initialize(userId);
|
|
27
27
|
},
|
|
@@ -31,20 +31,18 @@ export const useInitializeSubscription = (userId: string | undefined) => {
|
|
|
31
31
|
queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
34
|
+
if (__DEV__) {
|
|
35
|
+
console.log('[DEBUG useInitializeSubscription] Success:', { userId });
|
|
36
|
+
}
|
|
38
37
|
}
|
|
39
38
|
},
|
|
40
39
|
onError: (error) => {
|
|
41
|
-
|
|
42
|
-
{
|
|
43
|
-
|
|
44
|
-
operation: "initialize_mutation",
|
|
40
|
+
if (__DEV__) {
|
|
41
|
+
console.error('[DEBUG useInitializeSubscription] Error:', {
|
|
42
|
+
error,
|
|
45
43
|
userId: userId ?? "ANONYMOUS",
|
|
46
|
-
}
|
|
47
|
-
|
|
44
|
+
});
|
|
45
|
+
}
|
|
48
46
|
},
|
|
49
47
|
});
|
|
50
48
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paywall Flow Hook
|
|
3
|
+
* Manages post-onboarding paywall state with persistence
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
7
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
8
|
+
|
|
9
|
+
const PAYWALL_SHOWN_KEY = 'post_onboarding_paywall_shown';
|
|
10
|
+
|
|
11
|
+
export interface UsePaywallFlowOptions {
|
|
12
|
+
showAfterOnboarding?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface UsePaywallFlowResult {
|
|
16
|
+
showPostOnboardingPaywall: boolean;
|
|
17
|
+
paywallShown: boolean;
|
|
18
|
+
closePostOnboardingPaywall: (isPremium: boolean) => Promise<void>;
|
|
19
|
+
hidePostOnboardingPaywall: () => void;
|
|
20
|
+
markPaywallShown: () => Promise<void>;
|
|
21
|
+
setShowPostOnboardingPaywall: (show: boolean) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const usePaywallFlow = (options: UsePaywallFlowOptions = {}): UsePaywallFlowResult => {
|
|
25
|
+
const { showAfterOnboarding = false } = options;
|
|
26
|
+
const [showPostOnboardingPaywall, setShowPostOnboardingPaywall] = useState(showAfterOnboarding);
|
|
27
|
+
const [paywallShown, setPaywallShown] = useState(false);
|
|
28
|
+
|
|
29
|
+
// Load persisted state
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const loadPersistedState = async () => {
|
|
32
|
+
const value = await AsyncStorage.getItem(PAYWALL_SHOWN_KEY);
|
|
33
|
+
setPaywallShown(value === 'true');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
loadPersistedState();
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
const closePostOnboardingPaywall = useCallback(async (isPremium: boolean) => {
|
|
40
|
+
await AsyncStorage.setItem(PAYWALL_SHOWN_KEY, 'true');
|
|
41
|
+
setShowPostOnboardingPaywall(false);
|
|
42
|
+
setPaywallShown(true);
|
|
43
|
+
}, []);
|
|
44
|
+
|
|
45
|
+
const hidePostOnboardingPaywall = useCallback(() => {
|
|
46
|
+
setShowPostOnboardingPaywall(false);
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
const markPaywallShown = useCallback(async () => {
|
|
50
|
+
await AsyncStorage.setItem(PAYWALL_SHOWN_KEY, 'true');
|
|
51
|
+
setPaywallShown(true);
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
showPostOnboardingPaywall,
|
|
56
|
+
paywallShown,
|
|
57
|
+
closePostOnboardingPaywall,
|
|
58
|
+
hidePostOnboardingPaywall,
|
|
59
|
+
markPaywallShown,
|
|
60
|
+
setShowPostOnboardingPaywall,
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
8
8
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
9
9
|
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
10
|
-
import {
|
|
11
10
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
12
11
|
import { creditsQueryKeys } from "../../../presentation/hooks/useCredits";
|
|
13
12
|
|
|
@@ -31,23 +30,32 @@ export const usePurchasePackage = (userId: string | undefined) => {
|
|
|
31
30
|
|
|
32
31
|
const productId = pkg.product.identifier;
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
userId,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const success = await SubscriptionManager.purchasePackage(pkg);
|
|
40
|
-
|
|
41
|
-
if (success) {
|
|
33
|
+
if (__DEV__) {
|
|
34
|
+
console.log('[DEBUG usePurchasePackage] Starting purchase:', {
|
|
42
35
|
packageId: pkg.identifier,
|
|
43
36
|
productId,
|
|
44
37
|
userId,
|
|
45
38
|
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const success = await SubscriptionManager.purchasePackage(pkg);
|
|
42
|
+
|
|
43
|
+
if (success) {
|
|
44
|
+
if (__DEV__) {
|
|
45
|
+
console.log('[DEBUG usePurchasePackage] Purchase successful:', {
|
|
46
|
+
packageId: pkg.identifier,
|
|
47
|
+
productId,
|
|
48
|
+
userId,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
46
51
|
// Credits will be initialized by CustomerInfoListener
|
|
47
52
|
} else {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
if (__DEV__) {
|
|
54
|
+
console.log('[DEBUG usePurchasePackage] Purchase failed:', {
|
|
55
|
+
packageId: pkg.identifier,
|
|
56
|
+
userId,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
return { success, productId };
|
|
@@ -65,13 +73,12 @@ export const usePurchasePackage = (userId: string | undefined) => {
|
|
|
65
73
|
}
|
|
66
74
|
},
|
|
67
75
|
onError: (error) => {
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
|
|
71
|
-
operation: "purchase_mutation",
|
|
76
|
+
if (__DEV__) {
|
|
77
|
+
console.error('[DEBUG usePurchasePackage] Purchase mutation failed:', {
|
|
78
|
+
error,
|
|
72
79
|
userId: userId ?? "ANONYMOUS",
|
|
73
|
-
}
|
|
74
|
-
|
|
80
|
+
});
|
|
81
|
+
}
|
|
75
82
|
},
|
|
76
83
|
});
|
|
77
84
|
};
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
8
8
|
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
9
|
-
import {
|
|
10
9
|
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
11
10
|
import { creditsQueryKeys } from "../../../presentation/hooks/useCredits";
|
|
12
11
|
|
|
@@ -28,19 +27,24 @@ export const useRestorePurchase = (userId: string | undefined) => {
|
|
|
28
27
|
throw new Error("User not authenticated");
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
if (__DEV__) {
|
|
31
|
+
console.log('[DEBUG useRestorePurchase] Starting restore:', { userId });
|
|
32
|
+
}
|
|
33
33
|
|
|
34
34
|
const result = await SubscriptionManager.restore();
|
|
35
35
|
|
|
36
36
|
if (result.success) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (__DEV__) {
|
|
38
|
+
console.log('[DEBUG useRestorePurchase] Restore successful:', {
|
|
39
|
+
userId,
|
|
40
|
+
productId: result.productId,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
40
43
|
// Credits will be initialized by CustomerInfoListener
|
|
41
44
|
} else {
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
if (__DEV__) {
|
|
46
|
+
console.log('[DEBUG useRestorePurchase] Restore failed:', { userId });
|
|
47
|
+
}
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
return result;
|
|
@@ -58,13 +62,12 @@ export const useRestorePurchase = (userId: string | undefined) => {
|
|
|
58
62
|
}
|
|
59
63
|
},
|
|
60
64
|
onError: (error) => {
|
|
61
|
-
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
operation: "restore_mutation",
|
|
65
|
+
if (__DEV__) {
|
|
66
|
+
console.error('[DEBUG useRestorePurchase] Restore mutation failed:', {
|
|
67
|
+
error,
|
|
65
68
|
userId: userId ?? "ANONYMOUS",
|
|
66
|
-
}
|
|
67
|
-
|
|
69
|
+
});
|
|
70
|
+
}
|
|
68
71
|
},
|
|
69
72
|
});
|
|
70
73
|
};
|
|
@@ -32,9 +32,6 @@ export const useSubscriptionPackages = (userId: string | undefined) => {
|
|
|
32
32
|
console.log('[DEBUG useSubscriptionPackages] QueryFn executing...', { userId: userId || 'ANONYMOUS' });
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
userId: userId ?? "ANONYMOUS",
|
|
36
|
-
});
|
|
37
|
-
|
|
38
35
|
// Initialize if needed (works for both authenticated and anonymous users)
|
|
39
36
|
try {
|
|
40
37
|
if (userId) {
|
|
@@ -83,10 +80,6 @@ export const useSubscriptionPackages = (userId: string | undefined) => {
|
|
|
83
80
|
});
|
|
84
81
|
}
|
|
85
82
|
|
|
86
|
-
userId: userId ?? "ANONYMOUS",
|
|
87
|
-
count: packages.length,
|
|
88
|
-
});
|
|
89
|
-
|
|
90
83
|
return packages;
|
|
91
84
|
},
|
|
92
85
|
staleTime: STALE_TIME,
|