@umituz/react-native-subscription 2.6.1 → 2.7.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-subscription",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
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",
package/src/index.ts CHANGED
@@ -317,3 +317,11 @@ export {
317
317
 
318
318
  export { useRevenueCat } from "./revenuecat/presentation/hooks/useRevenueCat";
319
319
  export type { UseRevenueCatResult } from "./revenuecat/presentation/hooks/useRevenueCat";
320
+
321
+ export {
322
+ useInitializeSubscription,
323
+ useSubscriptionPackages,
324
+ usePurchasePackage,
325
+ useRestorePurchase,
326
+ SUBSCRIPTION_QUERY_KEYS,
327
+ } from "./revenuecat/presentation/hooks/useSubscriptionQueries";
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Subscription TanStack Query Hooks
3
+ * Server state management for RevenueCat subscriptions
4
+ * Generic hooks for 100+ apps
5
+ */
6
+
7
+ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
8
+ import type { PurchasesPackage } from "react-native-purchases";
9
+ import { SubscriptionManager } from "../../infrastructure/managers/SubscriptionManager";
10
+ import {
11
+ trackPackageError,
12
+ addPackageBreadcrumb,
13
+ } from "@umituz/react-native-sentry";
14
+
15
+ /**
16
+ * Query keys for TanStack Query
17
+ */
18
+ export const SUBSCRIPTION_QUERY_KEYS = {
19
+ packages: ["subscription", "packages"] as const,
20
+ initialized: (userId: string) =>
21
+ ["subscription", "initialized", userId] as const,
22
+ } as const;
23
+
24
+ const STALE_TIME = 5 * 60 * 1000; // 5 minutes
25
+ const GC_TIME = 30 * 60 * 1000; // 30 minutes
26
+
27
+ /**
28
+ * Initialize subscription with RevenueCat
29
+ */
30
+ export const useInitializeSubscription = (userId: string | undefined) => {
31
+ const queryClient = useQueryClient();
32
+
33
+ return useMutation({
34
+ mutationFn: async () => {
35
+ if (!userId) {
36
+ throw new Error("User not authenticated");
37
+ }
38
+
39
+ addPackageBreadcrumb("subscription", "Initialize mutation started", {
40
+ userId,
41
+ });
42
+
43
+ return SubscriptionManager.initialize(userId);
44
+ },
45
+ onSuccess: () => {
46
+ if (userId) {
47
+ queryClient.invalidateQueries({
48
+ queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
49
+ });
50
+
51
+ addPackageBreadcrumb(
52
+ "subscription",
53
+ "Initialize mutation success - packages invalidated",
54
+ { userId }
55
+ );
56
+ }
57
+ },
58
+ onError: (error) => {
59
+ trackPackageError(
60
+ error instanceof Error ? error : new Error(String(error)),
61
+ {
62
+ packageName: "subscription",
63
+ operation: "initialize_mutation",
64
+ userId: userId ?? "NO_USER",
65
+ }
66
+ );
67
+ },
68
+ });
69
+ };
70
+
71
+ /**
72
+ * Fetch available subscription packages
73
+ */
74
+ export const useSubscriptionPackages = (userId: string | undefined) => {
75
+ return useQuery({
76
+ queryKey: [...SUBSCRIPTION_QUERY_KEYS.packages, userId] as const,
77
+ queryFn: async () => {
78
+ addPackageBreadcrumb("subscription", "Fetch packages query started", {
79
+ userId: userId ?? "NO_USER",
80
+ });
81
+
82
+ // Skip if already initialized for this specific user
83
+ if (!userId || !SubscriptionManager.isInitializedForUser(userId)) {
84
+ await SubscriptionManager.initialize(userId);
85
+ }
86
+
87
+ const packages = await SubscriptionManager.getPackages();
88
+
89
+ addPackageBreadcrumb("subscription", "Fetch packages query success", {
90
+ userId: userId ?? "NO_USER",
91
+ count: packages.length,
92
+ });
93
+
94
+ return packages;
95
+ },
96
+ staleTime: STALE_TIME,
97
+ gcTime: GC_TIME,
98
+ enabled: !!userId, // Only run when userId is available
99
+ });
100
+ };
101
+
102
+ /**
103
+ * Purchase a subscription package
104
+ */
105
+ export const usePurchasePackage = (userId: string | undefined) => {
106
+ const queryClient = useQueryClient();
107
+
108
+ return useMutation({
109
+ mutationFn: async (pkg: PurchasesPackage) => {
110
+ if (!userId) {
111
+ throw new Error("User not authenticated");
112
+ }
113
+
114
+ addPackageBreadcrumb("subscription", "Purchase mutation started", {
115
+ packageId: pkg.identifier,
116
+ userId,
117
+ });
118
+
119
+ const success = await SubscriptionManager.purchasePackage(pkg);
120
+
121
+ if (success) {
122
+ addPackageBreadcrumb("subscription", "Purchase mutation success", {
123
+ packageId: pkg.identifier,
124
+ userId,
125
+ });
126
+ } else {
127
+ addPackageBreadcrumb("subscription", "Purchase mutation failed", {
128
+ packageId: pkg.identifier,
129
+ userId,
130
+ });
131
+ }
132
+
133
+ return success;
134
+ },
135
+ onSuccess: () => {
136
+ queryClient.invalidateQueries({
137
+ queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
138
+ });
139
+ },
140
+ onError: (error) => {
141
+ trackPackageError(
142
+ error instanceof Error ? error : new Error(String(error)),
143
+ {
144
+ packageName: "subscription",
145
+ operation: "purchase_mutation",
146
+ userId: userId ?? "NO_USER",
147
+ }
148
+ );
149
+ },
150
+ });
151
+ };
152
+
153
+ /**
154
+ * Restore previous purchases
155
+ */
156
+ export const useRestorePurchase = (userId: string | undefined) => {
157
+ const queryClient = useQueryClient();
158
+
159
+ return useMutation({
160
+ mutationFn: async () => {
161
+ if (!userId) {
162
+ throw new Error("User not authenticated");
163
+ }
164
+
165
+ addPackageBreadcrumb("subscription", "Restore mutation started", {
166
+ userId,
167
+ });
168
+
169
+ const success = await SubscriptionManager.restore();
170
+
171
+ if (success) {
172
+ addPackageBreadcrumb("subscription", "Restore mutation success", {
173
+ userId,
174
+ });
175
+ } else {
176
+ addPackageBreadcrumb("subscription", "Restore mutation failed", {
177
+ userId,
178
+ });
179
+ }
180
+
181
+ return success;
182
+ },
183
+ onSuccess: () => {
184
+ queryClient.invalidateQueries({
185
+ queryKey: SUBSCRIPTION_QUERY_KEYS.packages,
186
+ });
187
+ },
188
+ onError: (error) => {
189
+ trackPackageError(
190
+ error instanceof Error ? error : new Error(String(error)),
191
+ {
192
+ packageName: "subscription",
193
+ operation: "restore_mutation",
194
+ userId: userId ?? "NO_USER",
195
+ }
196
+ );
197
+ },
198
+ });
199
+ };