@umituz/react-native-subscription 2.11.6 → 2.11.8
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/presentation/components/details/CreditRow.tsx +83 -0
- package/src/presentation/components/details/DetailRow.tsx +53 -0
- package/src/presentation/components/details/PremiumDetailsCard.tsx +5 -155
- package/src/presentation/components/details/PremiumDetailsCardTypes.ts +41 -0
- package/src/presentation/components/paywall/BestValueBadge.tsx +0 -1
- package/src/presentation/components/paywall/PaywallFeaturesList.tsx +0 -3
- package/src/presentation/components/paywall/PaywallLegalFooter.tsx +5 -62
- package/src/presentation/components/paywall/PaywallLegalFooterStyles.ts +53 -0
- package/src/presentation/components/paywall/PaywallLegalFooterTypes.ts +19 -0
- package/src/presentation/components/paywall/PaywallModal.tsx +1 -1
- package/src/presentation/components/paywall/SubscriptionFooter.tsx +2 -6
- package/src/presentation/components/paywall/SubscriptionModal.tsx +0 -10
- package/src/presentation/components/paywall/SubscriptionPlanCard.tsx +5 -68
- package/src/presentation/components/paywall/SubscriptionPlanCardStyles.ts +61 -0
- package/src/presentation/components/paywall/SubscriptionPlanCardTypes.ts +15 -0
- package/src/presentation/hooks/useDeductCredit.ts +5 -4
- package/src/presentation/hooks/usePremiumWithConfig.ts +2 -1
- package/src/presentation/hooks/useSubscriptionModal.ts +2 -2
- package/src/revenuecat/presentation/hooks/subscriptionQueryKeys.ts +16 -0
- package/src/revenuecat/presentation/hooks/useInitializeSubscription.ts +56 -0
- package/src/revenuecat/presentation/hooks/usePurchasePackage.ts +79 -0
- package/src/revenuecat/presentation/hooks/useRestorePurchase.ts +68 -0
- package/src/revenuecat/presentation/hooks/useSubscriptionPackages.ts +44 -0
- package/src/revenuecat/presentation/hooks/useSubscriptionQueries.ts +9 -216
|
@@ -4,26 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
|
-
import { View, TouchableOpacity
|
|
8
|
-
import type { PurchasesPackage } from "react-native-purchases";
|
|
7
|
+
import { View, TouchableOpacity } from "react-native";
|
|
9
8
|
import { AtomicText } from "@umituz/react-native-design-system";
|
|
10
9
|
import { useAppDesignTokens, withAlpha } from "@umituz/react-native-design-system";
|
|
11
10
|
import { formatPrice } from "../../../utils/priceUtils";
|
|
12
11
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
13
12
|
import { BestValueBadge } from "./BestValueBadge";
|
|
14
|
-
|
|
15
13
|
import { getPeriodLabel, isYearlyPackage } from "../../../utils/packagePeriodUtils";
|
|
16
|
-
// @ts-ignore
|
|
17
14
|
import { LinearGradient } from "expo-linear-gradient";
|
|
15
|
+
import type { SubscriptionPlanCardProps } from "./SubscriptionPlanCardTypes";
|
|
16
|
+
import { styles } from "./SubscriptionPlanCardStyles";
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
package: PurchasesPackage;
|
|
21
|
-
isSelected: boolean;
|
|
22
|
-
onSelect: () => void;
|
|
23
|
-
isBestValue?: boolean;
|
|
24
|
-
/** Optional: Number of credits/generations included with this package */
|
|
25
|
-
creditAmount?: number;
|
|
26
|
-
}
|
|
18
|
+
export type { SubscriptionPlanCardProps } from "./SubscriptionPlanCardTypes";
|
|
27
19
|
|
|
28
20
|
export const SubscriptionPlanCard: React.FC<SubscriptionPlanCardProps> =
|
|
29
21
|
React.memo(({ package: pkg, isSelected, onSelect, isBestValue = false, creditAmount }) => {
|
|
@@ -148,59 +140,4 @@ export const SubscriptionPlanCard: React.FC<SubscriptionPlanCardProps> =
|
|
|
148
140
|
});
|
|
149
141
|
|
|
150
142
|
|
|
151
|
-
SubscriptionPlanCard.displayName = "SubscriptionPlanCard";
|
|
152
|
-
|
|
153
|
-
const styles = StyleSheet.create({
|
|
154
|
-
container: {
|
|
155
|
-
borderRadius: 16,
|
|
156
|
-
position: "relative",
|
|
157
|
-
overflow: "hidden", // Important for gradient borders/corners
|
|
158
|
-
},
|
|
159
|
-
gradientWrapper: {
|
|
160
|
-
flex: 1,
|
|
161
|
-
padding: 18,
|
|
162
|
-
},
|
|
163
|
-
content: {
|
|
164
|
-
flexDirection: "row",
|
|
165
|
-
justifyContent: "space-between",
|
|
166
|
-
alignItems: "center",
|
|
167
|
-
},
|
|
168
|
-
leftSection: {
|
|
169
|
-
flexDirection: "row",
|
|
170
|
-
alignItems: "center",
|
|
171
|
-
flex: 1,
|
|
172
|
-
},
|
|
173
|
-
radio: {
|
|
174
|
-
width: 24,
|
|
175
|
-
height: 24,
|
|
176
|
-
borderRadius: 12,
|
|
177
|
-
borderWidth: 2,
|
|
178
|
-
alignItems: "center",
|
|
179
|
-
justifyContent: "center",
|
|
180
|
-
marginRight: 16,
|
|
181
|
-
},
|
|
182
|
-
radioInner: {
|
|
183
|
-
width: 12,
|
|
184
|
-
height: 12,
|
|
185
|
-
borderRadius: 6,
|
|
186
|
-
},
|
|
187
|
-
textContainer: {
|
|
188
|
-
flex: 1,
|
|
189
|
-
},
|
|
190
|
-
title: {
|
|
191
|
-
fontWeight: "600",
|
|
192
|
-
marginBottom: 2,
|
|
193
|
-
},
|
|
194
|
-
creditBadge: {
|
|
195
|
-
paddingHorizontal: 10,
|
|
196
|
-
paddingVertical: 4,
|
|
197
|
-
borderRadius: 12,
|
|
198
|
-
marginBottom: 4,
|
|
199
|
-
},
|
|
200
|
-
rightSection: {
|
|
201
|
-
alignItems: "flex-end",
|
|
202
|
-
},
|
|
203
|
-
price: {
|
|
204
|
-
fontWeight: "700",
|
|
205
|
-
},
|
|
206
|
-
});
|
|
143
|
+
SubscriptionPlanCard.displayName = "SubscriptionPlanCard";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription Plan Card Styles
|
|
3
|
+
* StyleSheet definitions for subscription plan card
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { StyleSheet } from "react-native";
|
|
7
|
+
|
|
8
|
+
export const styles = StyleSheet.create({
|
|
9
|
+
container: {
|
|
10
|
+
borderRadius: 16,
|
|
11
|
+
position: "relative",
|
|
12
|
+
overflow: "hidden",
|
|
13
|
+
},
|
|
14
|
+
gradientWrapper: {
|
|
15
|
+
flex: 1,
|
|
16
|
+
padding: 18,
|
|
17
|
+
},
|
|
18
|
+
content: {
|
|
19
|
+
flexDirection: "row",
|
|
20
|
+
justifyContent: "space-between",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
},
|
|
23
|
+
leftSection: {
|
|
24
|
+
flexDirection: "row",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
flex: 1,
|
|
27
|
+
},
|
|
28
|
+
radio: {
|
|
29
|
+
width: 24,
|
|
30
|
+
height: 24,
|
|
31
|
+
borderRadius: 12,
|
|
32
|
+
borderWidth: 2,
|
|
33
|
+
alignItems: "center",
|
|
34
|
+
justifyContent: "center",
|
|
35
|
+
marginRight: 16,
|
|
36
|
+
},
|
|
37
|
+
radioInner: {
|
|
38
|
+
width: 12,
|
|
39
|
+
height: 12,
|
|
40
|
+
borderRadius: 6,
|
|
41
|
+
},
|
|
42
|
+
textContainer: {
|
|
43
|
+
flex: 1,
|
|
44
|
+
},
|
|
45
|
+
title: {
|
|
46
|
+
fontWeight: "600",
|
|
47
|
+
marginBottom: 2,
|
|
48
|
+
},
|
|
49
|
+
creditBadge: {
|
|
50
|
+
paddingHorizontal: 10,
|
|
51
|
+
paddingVertical: 4,
|
|
52
|
+
borderRadius: 12,
|
|
53
|
+
marginBottom: 4,
|
|
54
|
+
},
|
|
55
|
+
rightSection: {
|
|
56
|
+
alignItems: "flex-end",
|
|
57
|
+
},
|
|
58
|
+
price: {
|
|
59
|
+
fontWeight: "700",
|
|
60
|
+
},
|
|
61
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription Plan Card Types
|
|
3
|
+
* Type definitions for subscription plan display
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { PurchasesPackage } from "react-native-purchases";
|
|
7
|
+
|
|
8
|
+
export interface SubscriptionPlanCardProps {
|
|
9
|
+
package: PurchasesPackage;
|
|
10
|
+
isSelected: boolean;
|
|
11
|
+
onSelect: () => void;
|
|
12
|
+
isBestValue?: boolean;
|
|
13
|
+
/** Optional: Number of credits/generations included with this package */
|
|
14
|
+
creditAmount?: number;
|
|
15
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Generic and reusable - uses module-level repository.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { useCallback } from "react";
|
|
8
9
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
9
10
|
import type { CreditType, UserCredits } from "../../domain/entities/Credits";
|
|
10
11
|
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
@@ -78,7 +79,7 @@ export const useDeductCredit = ({
|
|
|
78
79
|
},
|
|
79
80
|
});
|
|
80
81
|
|
|
81
|
-
const deductCredit = async (creditType: CreditType): Promise<boolean> => {
|
|
82
|
+
const deductCredit = useCallback(async (creditType: CreditType): Promise<boolean> => {
|
|
82
83
|
try {
|
|
83
84
|
const result = await mutation.mutateAsync(creditType);
|
|
84
85
|
|
|
@@ -93,7 +94,7 @@ export const useDeductCredit = ({
|
|
|
93
94
|
} catch {
|
|
94
95
|
return false;
|
|
95
96
|
}
|
|
96
|
-
};
|
|
97
|
+
}, [mutation, onCreditsExhausted]);
|
|
97
98
|
|
|
98
99
|
return {
|
|
99
100
|
deductCredit,
|
|
@@ -135,14 +136,14 @@ export const useInitializeCredits = ({
|
|
|
135
136
|
},
|
|
136
137
|
});
|
|
137
138
|
|
|
138
|
-
const initializeCredits = async (purchaseId?: string): Promise<boolean> => {
|
|
139
|
+
const initializeCredits = useCallback(async (purchaseId?: string): Promise<boolean> => {
|
|
139
140
|
try {
|
|
140
141
|
const result = await mutation.mutateAsync(purchaseId);
|
|
141
142
|
return result.success;
|
|
142
143
|
} catch {
|
|
143
144
|
return false;
|
|
144
145
|
}
|
|
145
|
-
};
|
|
146
|
+
}, [mutation]);
|
|
146
147
|
|
|
147
148
|
return {
|
|
148
149
|
initializeCredits,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { useCallback } from "react";
|
|
9
9
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
10
|
+
import type { UserCredits } from "../../domain/entities/Credits";
|
|
10
11
|
import { useCredits } from "./useCredits";
|
|
11
12
|
import { useInitializeCredits } from "./useDeductCredit";
|
|
12
13
|
import {
|
|
@@ -27,7 +28,7 @@ export interface UsePremiumWithConfigResult {
|
|
|
27
28
|
isPremium: boolean;
|
|
28
29
|
isLoading: boolean;
|
|
29
30
|
packages: PurchasesPackage[];
|
|
30
|
-
credits:
|
|
31
|
+
credits: UserCredits | null;
|
|
31
32
|
showPaywall: boolean;
|
|
32
33
|
purchasePackage: (pkg: PurchasesPackage) => Promise<boolean>;
|
|
33
34
|
restorePurchase: () => Promise<boolean>;
|
|
@@ -23,7 +23,7 @@ export const useSubscriptionModal = ({
|
|
|
23
23
|
} finally {
|
|
24
24
|
setIsProcessing(false);
|
|
25
25
|
}
|
|
26
|
-
}, [selectedPkg,
|
|
26
|
+
}, [selectedPkg, onPurchase, onClose]);
|
|
27
27
|
|
|
28
28
|
const handleRestore = useCallback(async () => {
|
|
29
29
|
if (isProcessing) return;
|
|
@@ -33,7 +33,7 @@ export const useSubscriptionModal = ({
|
|
|
33
33
|
} finally {
|
|
34
34
|
setIsProcessing(false);
|
|
35
35
|
}
|
|
36
|
-
}, [
|
|
36
|
+
}, [onRestore, onClose]);
|
|
37
37
|
|
|
38
38
|
return {
|
|
39
39
|
selectedPkg,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription Query Keys
|
|
3
|
+
* TanStack Query keys and constants for subscription state
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Query keys for TanStack Query
|
|
8
|
+
*/
|
|
9
|
+
export const SUBSCRIPTION_QUERY_KEYS = {
|
|
10
|
+
packages: ["subscription", "packages"] as const,
|
|
11
|
+
initialized: (userId: string) =>
|
|
12
|
+
["subscription", "initialized", userId] as const,
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
export const STALE_TIME = 5 * 60 * 1000; // 5 minutes
|
|
16
|
+
export const GC_TIME = 30 * 60 * 1000; // 30 minutes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize Subscription Hook
|
|
3
|
+
* TanStack mutation for initializing RevenueCat
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
7
|
+
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
8
|
+
import {
|
|
9
|
+
trackPackageError,
|
|
10
|
+
addPackageBreadcrumb,
|
|
11
|
+
} from "@umituz/react-native-sentry";
|
|
12
|
+
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Initialize subscription with RevenueCat
|
|
16
|
+
*/
|
|
17
|
+
export const useInitializeSubscription = (userId: string | undefined) => {
|
|
18
|
+
const queryClient = useQueryClient();
|
|
19
|
+
|
|
20
|
+
return useMutation({
|
|
21
|
+
mutationFn: async () => {
|
|
22
|
+
if (!userId) {
|
|
23
|
+
throw new Error("User not authenticated");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
addPackageBreadcrumb("subscription", "Initialize mutation started", {
|
|
27
|
+
userId,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return SubscriptionManager.initialize(userId);
|
|
31
|
+
},
|
|
32
|
+
onSuccess: () => {
|
|
33
|
+
if (userId) {
|
|
34
|
+
queryClient.invalidateQueries({
|
|
35
|
+
queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
addPackageBreadcrumb(
|
|
39
|
+
"subscription",
|
|
40
|
+
"Initialize mutation success - packages invalidated",
|
|
41
|
+
{ userId }
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
onError: (error) => {
|
|
46
|
+
trackPackageError(
|
|
47
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
48
|
+
{
|
|
49
|
+
packageName: "subscription",
|
|
50
|
+
operation: "initialize_mutation",
|
|
51
|
+
userId: userId ?? "NO_USER",
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purchase Package Hook
|
|
3
|
+
* TanStack mutation for purchasing subscription packages
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
7
|
+
import type { PurchasesPackage } from "react-native-purchases";
|
|
8
|
+
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
9
|
+
import {
|
|
10
|
+
trackPackageError,
|
|
11
|
+
addPackageBreadcrumb,
|
|
12
|
+
} from "@umituz/react-native-sentry";
|
|
13
|
+
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Purchase a subscription package
|
|
17
|
+
*/
|
|
18
|
+
export const usePurchasePackage = (userId: string | undefined) => {
|
|
19
|
+
const queryClient = useQueryClient();
|
|
20
|
+
|
|
21
|
+
return useMutation({
|
|
22
|
+
mutationFn: async (pkg: PurchasesPackage) => {
|
|
23
|
+
if (!userId) {
|
|
24
|
+
throw new Error("User not authenticated");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
addPackageBreadcrumb("subscription", "Purchase started", {
|
|
28
|
+
packageId: pkg.identifier,
|
|
29
|
+
userId,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
addPackageBreadcrumb("subscription", "Purchase mutation started", {
|
|
33
|
+
packageId: pkg.identifier,
|
|
34
|
+
userId,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const success = await SubscriptionManager.purchasePackage(pkg);
|
|
38
|
+
|
|
39
|
+
if (success) {
|
|
40
|
+
addPackageBreadcrumb("subscription", "Purchase success", {
|
|
41
|
+
packageId: pkg.identifier,
|
|
42
|
+
userId,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
addPackageBreadcrumb("subscription", "Purchase mutation success", {
|
|
46
|
+
packageId: pkg.identifier,
|
|
47
|
+
userId,
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
addPackageBreadcrumb("subscription", "Purchase cancelled", {
|
|
51
|
+
packageId: pkg.identifier,
|
|
52
|
+
userId,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
addPackageBreadcrumb("subscription", "Purchase mutation failed", {
|
|
56
|
+
packageId: pkg.identifier,
|
|
57
|
+
userId,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return success;
|
|
62
|
+
},
|
|
63
|
+
onSuccess: () => {
|
|
64
|
+
queryClient.invalidateQueries({
|
|
65
|
+
queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
onError: (error) => {
|
|
69
|
+
trackPackageError(
|
|
70
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
71
|
+
{
|
|
72
|
+
packageName: "subscription",
|
|
73
|
+
operation: "purchase_mutation",
|
|
74
|
+
userId: userId ?? "NO_USER",
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Restore Purchase Hook
|
|
3
|
+
* TanStack mutation for restoring previous purchases
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
7
|
+
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
8
|
+
import {
|
|
9
|
+
trackPackageError,
|
|
10
|
+
addPackageBreadcrumb,
|
|
11
|
+
} from "@umituz/react-native-sentry";
|
|
12
|
+
import { SUBSCRIPTION_QUERY_KEYS } from "./subscriptionQueryKeys";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Restore previous purchases
|
|
16
|
+
*/
|
|
17
|
+
export const useRestorePurchase = (userId: string | undefined) => {
|
|
18
|
+
const queryClient = useQueryClient();
|
|
19
|
+
|
|
20
|
+
return useMutation({
|
|
21
|
+
mutationFn: async () => {
|
|
22
|
+
if (!userId) {
|
|
23
|
+
throw new Error("User not authenticated");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
addPackageBreadcrumb("subscription", "Restore started", {
|
|
27
|
+
userId,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
addPackageBreadcrumb("subscription", "Restore mutation started", {
|
|
31
|
+
userId,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const success = await SubscriptionManager.restore();
|
|
35
|
+
|
|
36
|
+
if (success) {
|
|
37
|
+
addPackageBreadcrumb("subscription", "Restore success", {
|
|
38
|
+
userId,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
addPackageBreadcrumb("subscription", "Restore mutation success", {
|
|
42
|
+
userId,
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
addPackageBreadcrumb("subscription", "Restore mutation failed", {
|
|
46
|
+
userId,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return success;
|
|
51
|
+
},
|
|
52
|
+
onSuccess: () => {
|
|
53
|
+
queryClient.invalidateQueries({
|
|
54
|
+
queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
onError: (error) => {
|
|
58
|
+
trackPackageError(
|
|
59
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
60
|
+
{
|
|
61
|
+
packageName: "subscription",
|
|
62
|
+
operation: "restore_mutation",
|
|
63
|
+
userId: userId ?? "NO_USER",
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription Packages Hook
|
|
3
|
+
* TanStack query for fetching available packages
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useQuery } from "@tanstack/react-query";
|
|
7
|
+
import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
|
|
8
|
+
import { addPackageBreadcrumb } from "@umituz/react-native-sentry";
|
|
9
|
+
import {
|
|
10
|
+
SUBSCRIPTION_QUERY_KEYS,
|
|
11
|
+
STALE_TIME,
|
|
12
|
+
GC_TIME,
|
|
13
|
+
} from "./subscriptionQueryKeys";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Fetch available subscription packages
|
|
17
|
+
*/
|
|
18
|
+
export const useSubscriptionPackages = (userId: string | undefined) => {
|
|
19
|
+
return useQuery({
|
|
20
|
+
queryKey: [...SUBSCRIPTION_QUERY_KEYS.packages, userId] as const,
|
|
21
|
+
queryFn: async () => {
|
|
22
|
+
addPackageBreadcrumb("subscription", "Fetch packages query started", {
|
|
23
|
+
userId: userId ?? "NO_USER",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Skip if already initialized for this specific user
|
|
27
|
+
if (!userId || !SubscriptionManager.isInitializedForUser(userId)) {
|
|
28
|
+
await SubscriptionManager.initialize(userId);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const packages = await SubscriptionManager.getPackages();
|
|
32
|
+
|
|
33
|
+
addPackageBreadcrumb("subscription", "Fetch packages query success", {
|
|
34
|
+
userId: userId ?? "NO_USER",
|
|
35
|
+
count: packages.length,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return packages;
|
|
39
|
+
},
|
|
40
|
+
staleTime: STALE_TIME,
|
|
41
|
+
gcTime: GC_TIME,
|
|
42
|
+
enabled: !!userId, // Only run when userId is available
|
|
43
|
+
});
|
|
44
|
+
};
|