@umituz/react-native-subscription 2.14.96 → 2.14.98
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/LICENSE +21 -0
- package/README.md +462 -0
- package/package.json +3 -3
- package/src/application/README.md +229 -0
- package/src/application/ports/README.md +103 -0
- package/src/domain/README.md +402 -0
- package/src/domain/constants/README.md +80 -0
- package/src/domain/entities/README.md +176 -0
- package/src/domain/errors/README.md +307 -0
- package/src/domain/value-objects/README.md +186 -0
- package/src/domains/config/README.md +390 -0
- package/src/domains/paywall/README.md +371 -0
- package/src/domains/paywall/components/PaywallHeader.tsx +8 -11
- package/src/domains/paywall/components/README.md +185 -0
- package/src/domains/paywall/entities/README.md +199 -0
- package/src/domains/paywall/hooks/README.md +129 -0
- package/src/domains/wallet/README.md +292 -0
- package/src/domains/wallet/domain/README.md +108 -0
- package/src/domains/wallet/domain/entities/README.md +122 -0
- package/src/domains/wallet/domain/errors/README.md +157 -0
- package/src/domains/wallet/infrastructure/README.md +96 -0
- package/src/domains/wallet/presentation/components/BalanceCard.tsx +6 -12
- package/src/domains/wallet/presentation/components/README.md +231 -0
- package/src/domains/wallet/presentation/hooks/README.md +255 -0
- package/src/infrastructure/README.md +514 -0
- package/src/infrastructure/mappers/README.md +34 -0
- package/src/infrastructure/models/README.md +26 -0
- package/src/infrastructure/repositories/README.md +385 -0
- package/src/infrastructure/services/README.md +374 -0
- package/src/presentation/README.md +410 -0
- package/src/presentation/components/README.md +183 -0
- package/src/presentation/components/details/CreditRow.md +337 -0
- package/src/presentation/components/details/DetailRow.md +283 -0
- package/src/presentation/components/details/PremiumDetailsCard.md +266 -0
- package/src/presentation/components/details/PremiumStatusBadge.md +266 -0
- package/src/presentation/components/details/README.md +449 -0
- package/src/presentation/components/feedback/PaywallFeedbackModal.md +314 -0
- package/src/presentation/components/feedback/README.md +447 -0
- package/src/presentation/components/paywall/PaywallModal.md +444 -0
- package/src/presentation/components/paywall/README.md +190 -0
- package/src/presentation/components/sections/README.md +468 -0
- package/src/presentation/components/sections/SubscriptionSection.md +246 -0
- package/src/presentation/hooks/README.md +743 -0
- package/src/presentation/hooks/useAuthAwarePurchase.md +359 -0
- package/src/presentation/hooks/useAuthGate.md +403 -0
- package/src/presentation/hooks/useAuthSubscriptionSync.md +398 -0
- package/src/presentation/hooks/useCreditChecker.md +407 -0
- package/src/presentation/hooks/useCredits.md +342 -0
- package/src/presentation/hooks/useCreditsGate.md +346 -0
- package/src/presentation/hooks/useDeductCredit.md +160 -0
- package/src/presentation/hooks/useDevTestCallbacks.md +422 -0
- package/src/presentation/hooks/useFeatureGate.md +157 -0
- package/src/presentation/hooks/useInitializeCredits.md +458 -0
- package/src/presentation/hooks/usePaywall.md +334 -0
- package/src/presentation/hooks/usePaywallOperations.md +486 -0
- package/src/presentation/hooks/usePaywallVisibility.md +344 -0
- package/src/presentation/hooks/usePremium.md +230 -0
- package/src/presentation/hooks/usePremiumGate.md +423 -0
- package/src/presentation/hooks/usePremiumWithCredits.md +429 -0
- package/src/presentation/hooks/useSubscription.md +450 -0
- package/src/presentation/hooks/useSubscriptionDetails.md +438 -0
- package/src/presentation/hooks/useSubscriptionGate.md +168 -0
- package/src/presentation/hooks/useSubscriptionSettingsConfig.md +374 -0
- package/src/presentation/hooks/useSubscriptionStatus.md +424 -0
- package/src/presentation/hooks/useUserTier.md +356 -0
- package/src/presentation/hooks/useUserTierWithRepository.md +452 -0
- package/src/presentation/screens/README.md +194 -0
- package/src/presentation/types/README.md +38 -0
- package/src/presentation/utils/README.md +52 -0
- package/src/revenuecat/README.md +523 -0
- package/src/revenuecat/domain/README.md +147 -0
- package/src/revenuecat/domain/errors/README.md +197 -0
- package/src/revenuecat/infrastructure/config/README.md +40 -0
- package/src/revenuecat/infrastructure/managers/README.md +49 -0
- package/src/revenuecat/presentation/hooks/README.md +56 -0
- package/src/revenuecat/presentation/hooks/usePurchasePackage.ts +1 -1
- package/src/utils/README.md +529 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# useAuthAwarePurchase Hook
|
|
2
|
+
|
|
3
|
+
Security-focused purchase hook that requires authentication before any transaction.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import {
|
|
9
|
+
useAuthAwarePurchase,
|
|
10
|
+
configureAuthProvider
|
|
11
|
+
} from '@umituz/react-native-subscription';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Configuration
|
|
15
|
+
|
|
16
|
+
**IMPORTANT**: You must configure the auth provider once at app initialization:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { configureAuthProvider } from '@umituz/react-native-subscription';
|
|
20
|
+
|
|
21
|
+
// Configure once at app startup
|
|
22
|
+
configureAuthProvider({
|
|
23
|
+
isAuthenticated: () => {
|
|
24
|
+
// Return true if user is authenticated
|
|
25
|
+
return auth.currentUser != null;
|
|
26
|
+
},
|
|
27
|
+
showAuthModal: () => {
|
|
28
|
+
// Show your authentication modal/screen
|
|
29
|
+
navigation.navigate('Auth');
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Signature
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
function useAuthAwarePurchase(): {
|
|
38
|
+
handlePurchase: (pkg: PurchasesPackage) => Promise<boolean>;
|
|
39
|
+
handleRestore: () => Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Returns
|
|
44
|
+
|
|
45
|
+
| Property | Type | Description |
|
|
46
|
+
|----------|------|-------------|
|
|
47
|
+
| `handlePurchase` | `(pkg) => Promise<boolean>` | Purchase with auth check |
|
|
48
|
+
| `handleRestore` | `() => Promise<boolean>` | Restore with auth check |
|
|
49
|
+
|
|
50
|
+
## Basic Usage
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
function PaywallScreen() {
|
|
54
|
+
const { handlePurchase, handleRestore } = useAuthAwarePurchase();
|
|
55
|
+
|
|
56
|
+
const onPurchasePress = async (package: PurchasesPackage) => {
|
|
57
|
+
const success = await handlePurchase(package);
|
|
58
|
+
if (success) {
|
|
59
|
+
console.log('Purchase successful');
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const onRestorePress = async () => {
|
|
64
|
+
const success = await handleRestore();
|
|
65
|
+
if (success) {
|
|
66
|
+
console.log('Restore successful');
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<View>
|
|
72
|
+
<PackageList onSelectPackage={onPurchasePress} />
|
|
73
|
+
<Button onPress={onRestorePress} title="Restore Purchases" />
|
|
74
|
+
</View>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Advanced Usage
|
|
80
|
+
|
|
81
|
+
### With Auth Provider Setup
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// App.tsx - Configure at app start
|
|
85
|
+
import { configureAuthProvider } from '@umituz/react-native-subscription';
|
|
86
|
+
import { auth } from './firebase/config';
|
|
87
|
+
|
|
88
|
+
export default function App() {
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
configureAuthProvider({
|
|
91
|
+
isAuthenticated: () => {
|
|
92
|
+
return auth.currentUser !== null;
|
|
93
|
+
},
|
|
94
|
+
showAuthModal: () => {
|
|
95
|
+
// Navigate to auth screen or show modal
|
|
96
|
+
navigationRef.current?.navigate('AuthModal', {
|
|
97
|
+
onAuthSuccess: () => {
|
|
98
|
+
// Paywall will be shown again after auth
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
105
|
+
return <YourAppNavigation />;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### With Custom Auth Logic
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// With your auth library
|
|
113
|
+
import { configureAuthProvider } from '@umituz/react-native-subscription';
|
|
114
|
+
import { useAuth } from '@umituz/react-native-auth';
|
|
115
|
+
|
|
116
|
+
export default function App() {
|
|
117
|
+
const { user, showAuthModal } = useAuth();
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
configureAuthProvider({
|
|
121
|
+
isAuthenticated: () => !!user,
|
|
122
|
+
showAuthModal: () => {
|
|
123
|
+
showAuthModal({
|
|
124
|
+
purpose: 'purchase',
|
|
125
|
+
message: 'Sign in to complete your purchase',
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}, [user, showAuthModal]);
|
|
130
|
+
|
|
131
|
+
return <YourApp />;
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### With Pending Purchase After Auth
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
function PaywallWithPendingPurchase() {
|
|
139
|
+
const { handlePurchase } = useAuthAwarePurchase();
|
|
140
|
+
const [pendingPackage, setPendingPackage] = useState<PurchasesPackage | null>(null);
|
|
141
|
+
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
// If user was not authenticated, purchase is intercepted
|
|
144
|
+
// After authentication, you can retry the purchase
|
|
145
|
+
if (user && pendingPackage) {
|
|
146
|
+
handlePurchase(pendingPackage).then((success) => {
|
|
147
|
+
if (success) {
|
|
148
|
+
setPendingPackage(null);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}, [user, pendingPackage]);
|
|
153
|
+
|
|
154
|
+
const onPurchasePress = async (pkg: PurchasesPackage) => {
|
|
155
|
+
const success = await handlePurchase(pkg);
|
|
156
|
+
if (!success && !user) {
|
|
157
|
+
// User needs to authenticate first
|
|
158
|
+
setPendingPackage(pkg);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
return <PackageList onSelectPackage={onPurchasePress} />;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### With Error Handling
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
function SecurePaywall() {
|
|
170
|
+
const { handlePurchase, handleRestore } = useAuthAwarePurchase();
|
|
171
|
+
|
|
172
|
+
const onPurchasePress = async (pkg: PurchasesPackage) => {
|
|
173
|
+
try {
|
|
174
|
+
const success = await handlePurchase(pkg);
|
|
175
|
+
|
|
176
|
+
if (!success) {
|
|
177
|
+
// Check if auth was the issue
|
|
178
|
+
if (!auth.currentUser) {
|
|
179
|
+
console.log('Purchase blocked - user not authenticated');
|
|
180
|
+
} else {
|
|
181
|
+
console.log('Purchase failed for other reasons');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error('Purchase error:', error);
|
|
186
|
+
Alert.alert('Error', 'Failed to complete purchase');
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<PaywallModal>
|
|
192
|
+
<PackageList onSelectPackage={onPurchasePress} />
|
|
193
|
+
</PaywallModal>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Security Features
|
|
199
|
+
|
|
200
|
+
### Auth Provider Required
|
|
201
|
+
|
|
202
|
+
The hook will **block all purchases** if auth provider is not configured:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// Development mode error
|
|
206
|
+
[useAuthAwarePurchase] CRITICAL: Auth provider not configured.
|
|
207
|
+
Call configureAuthProvider() at app start. Purchase blocked for security.
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Anonymous User Blocking
|
|
211
|
+
|
|
212
|
+
Purchases are automatically blocked for anonymous/guest users:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// Development mode log
|
|
216
|
+
[useAuthAwarePurchase] User not authenticated, opening auth modal
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Automatic Auth Flow
|
|
220
|
+
|
|
221
|
+
When an unauthenticated user tries to purchase:
|
|
222
|
+
|
|
223
|
+
1. Purchase is blocked
|
|
224
|
+
2. Auth modal is shown
|
|
225
|
+
3. User can authenticate
|
|
226
|
+
4. After auth, purchase can be retried
|
|
227
|
+
|
|
228
|
+
## Examples
|
|
229
|
+
|
|
230
|
+
### Complete Paywall Implementation
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
function PaywallScreen() {
|
|
234
|
+
const { handlePurchase, handleRestore } = useAuthAwarePurchase();
|
|
235
|
+
const { packages } = useSubscriptionPackages();
|
|
236
|
+
|
|
237
|
+
const [selectedPackage, setSelectedPackage] = useState<PurchasesPackage | null>(null);
|
|
238
|
+
const [isPurchasing, setIsPurchasing] = useState(false);
|
|
239
|
+
|
|
240
|
+
const handlePackageSelect = async (pkg: PurchasesPackage) => {
|
|
241
|
+
setSelectedPackage(pkg);
|
|
242
|
+
setIsPurchasing(true);
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const success = await handlePurchase(pkg);
|
|
246
|
+
|
|
247
|
+
if (success) {
|
|
248
|
+
Alert.alert('Success', 'You are now a Premium member!');
|
|
249
|
+
}
|
|
250
|
+
} catch (error) {
|
|
251
|
+
Alert.alert('Error', 'Purchase failed. Please try again.');
|
|
252
|
+
} finally {
|
|
253
|
+
setIsPurchasing(false);
|
|
254
|
+
setSelectedPackage(null);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const handleRestorePress = async () => {
|
|
259
|
+
const success = await handleRestore();
|
|
260
|
+
Alert.alert(
|
|
261
|
+
success ? 'Success' : 'Failed',
|
|
262
|
+
success ? 'Purchases restored' : 'No purchases found'
|
|
263
|
+
);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<ScrollView>
|
|
268
|
+
<PaywallHeader />
|
|
269
|
+
|
|
270
|
+
{packages.map((pkg) => (
|
|
271
|
+
<PackageCard
|
|
272
|
+
key={pkg.identifier}
|
|
273
|
+
package={pkg}
|
|
274
|
+
onSelect={handlePackageSelect}
|
|
275
|
+
disabled={isPurchasing}
|
|
276
|
+
selected={selectedPackage?.identifier === pkg.identifier}
|
|
277
|
+
/>
|
|
278
|
+
))}
|
|
279
|
+
|
|
280
|
+
<Button onPress={handleRestorePress} title="Restore Purchases" />
|
|
281
|
+
|
|
282
|
+
<TermsAndConditions />
|
|
283
|
+
</ScrollView>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### In-App Purchase Button
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
function InAppPurchaseButton({ productIdentifier }) {
|
|
292
|
+
const { handlePurchase } = useAuthAwarePurchase();
|
|
293
|
+
const { packages } = useSubscriptionPackages();
|
|
294
|
+
|
|
295
|
+
const pkg = packages.find((p) => p.identifier === productIdentifier);
|
|
296
|
+
|
|
297
|
+
const onPress = async () => {
|
|
298
|
+
if (!pkg) return;
|
|
299
|
+
|
|
300
|
+
const success = await handlePurchase(pkg);
|
|
301
|
+
|
|
302
|
+
if (success) {
|
|
303
|
+
onPurchaseSuccess?.();
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
return (
|
|
308
|
+
<Button
|
|
309
|
+
onPress={onPress}
|
|
310
|
+
title="Get Premium"
|
|
311
|
+
disabled={!pkg}
|
|
312
|
+
/>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Best Practices
|
|
318
|
+
|
|
319
|
+
1. **Configure early** - Set up auth provider at app initialization
|
|
320
|
+
2. **Test auth flow** - Verify purchases work for authenticated users
|
|
321
|
+
3. **Test guest flow** - Verify guests are prompted to sign in
|
|
322
|
+
4. **Handle failures** - Show user-friendly error messages
|
|
323
|
+
5. **Clear pending** - Reset pending purchase state after completion
|
|
324
|
+
6. **Security first** - Never bypass auth checks
|
|
325
|
+
7. **Development testing** - Use dev logs to verify auth checks work
|
|
326
|
+
|
|
327
|
+
## Security Considerations
|
|
328
|
+
|
|
329
|
+
### Why Auth Provider is Required
|
|
330
|
+
|
|
331
|
+
This hook implements a security-first approach to prevent:
|
|
332
|
+
|
|
333
|
+
1. **Anonymous purchases** - Guest users cannot make purchases
|
|
334
|
+
2. **Unauthorized transactions** - Only authenticated users can buy
|
|
335
|
+
3. **Payment fraud** - Reduces risk of fraudulent purchases
|
|
336
|
+
4. **Compliance** - Meets app store requirements for user identification
|
|
337
|
+
|
|
338
|
+
### Configuration Checklist
|
|
339
|
+
|
|
340
|
+
- [ ] Call `configureAuthProvider()` once at app startup
|
|
341
|
+
- [ ] Provide `isAuthenticated()` function
|
|
342
|
+
- [ ] Provide `showAuthModal()` function
|
|
343
|
+
- [ ] Test purchase flow with authenticated user
|
|
344
|
+
- [ ] Test purchase flow with unauthenticated user
|
|
345
|
+
- [ ] Verify development logs show auth checks
|
|
346
|
+
- [ ] Verify purchases are blocked without auth provider
|
|
347
|
+
|
|
348
|
+
## Related Hooks
|
|
349
|
+
|
|
350
|
+
- **usePremium** - For purchase and restore operations
|
|
351
|
+
- **usePaywallOperations** - For complete paywall purchase handling
|
|
352
|
+
- **useAuthGate** - For authentication gating
|
|
353
|
+
- **useAuthSubscriptionSync** - For syncing auth with subscription
|
|
354
|
+
|
|
355
|
+
## See Also
|
|
356
|
+
|
|
357
|
+
- [Auth Integration](../../hooks/useAuthSubscriptionSync.md)
|
|
358
|
+
- [Paywall Screen](../screens/README.md)
|
|
359
|
+
- [Security Best Practices](../../../docs/SECURITY.md)
|