@umituz/react-native-subscription 2.35.11 → 2.35.13
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/domains/paywall/components/PaywallContainer.tsx +8 -17
- package/src/domains/paywall/components/PaywallModal.tsx +11 -2
- package/src/domains/paywall/components/PaywallModal.types.ts +5 -0
- package/src/domains/paywall/hooks/usePaywallActions.ts +8 -26
- package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +0 -7
- package/src/domains/subscription/infrastructure/handlers/PurchaseStatusResolver.ts +0 -7
- package/src/domains/subscription/infrastructure/handlers/package-operations/PackagePurchaser.ts +0 -10
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +0 -10
- package/src/domains/subscription/infrastructure/managers/managerOperations.ts +0 -8
- package/src/domains/subscription/infrastructure/services/PurchaseHandler.ts +0 -15
- package/src/domains/subscription/infrastructure/services/RevenueCatService.types.ts +0 -8
- package/src/domains/subscription/infrastructure/services/purchase/PurchaseExecutor.ts +0 -11
- package/src/domains/subscription/presentation/screens/components/SubscriptionHeaderContent.tsx +3 -12
- package/src/utils/packageTypeDetector.test.ts +0 -70
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.35.
|
|
3
|
+
"version": "2.35.13",
|
|
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",
|
|
@@ -4,7 +4,6 @@ import { useSubscriptionPackages } from "../../subscription/infrastructure/hooks
|
|
|
4
4
|
import { useRevenueCatTrialEligibility } from "../../subscription/infrastructure/hooks/useRevenueCatTrialEligibility";
|
|
5
5
|
import { createCreditAmountsFromPackages } from "../../../utils/creditMapper";
|
|
6
6
|
import { PaywallModal } from "./PaywallModal";
|
|
7
|
-
import { usePaywallActions } from "../hooks/usePaywallActions";
|
|
8
7
|
import { useAuthAwarePurchase } from "../../subscription/presentation/useAuthAwarePurchase";
|
|
9
8
|
import { useTrialEligibilityCheck } from "../hooks/useTrialEligibilityCheck";
|
|
10
9
|
import type { PaywallContainerProps } from "./PaywallContainer.types";
|
|
@@ -36,20 +35,9 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
36
35
|
|
|
37
36
|
const { data: packages = [], isLoading } = useSubscriptionPackages();
|
|
38
37
|
const { eligibilityMap, checkEligibility } = useRevenueCatTrialEligibility();
|
|
39
|
-
|
|
40
|
-
const { handlePurchase: performPurchase, handleRestore: performRestore } = useAuthAwarePurchase({
|
|
41
|
-
source: purchaseSource
|
|
42
|
-
});
|
|
43
38
|
|
|
44
|
-
const { handlePurchase, handleRestore } =
|
|
45
|
-
|
|
46
|
-
onPurchase: performPurchase,
|
|
47
|
-
onRestore: performRestore,
|
|
48
|
-
source: purchaseSource,
|
|
49
|
-
onPurchaseSuccess,
|
|
50
|
-
onPurchaseError,
|
|
51
|
-
onAuthRequired,
|
|
52
|
-
onClose: handleClose,
|
|
39
|
+
const { handlePurchase: performPurchase, handleRestore: performRestore } = useAuthAwarePurchase({
|
|
40
|
+
source: purchaseSource
|
|
53
41
|
});
|
|
54
42
|
|
|
55
43
|
const trialEligibility = useTrialEligibilityCheck({
|
|
@@ -60,7 +48,6 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
60
48
|
trialConfig,
|
|
61
49
|
});
|
|
62
50
|
|
|
63
|
-
// Compute credit amounts from packageAllocations if not provided directly
|
|
64
51
|
const creditAmounts = useMemo(() => {
|
|
65
52
|
if (providedCreditAmounts) return providedCreditAmounts;
|
|
66
53
|
if (!packageAllocations || packages.length === 0) return undefined;
|
|
@@ -81,10 +68,14 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
81
68
|
bestValueIdentifier={bestValueIdentifier}
|
|
82
69
|
creditAmounts={creditAmounts}
|
|
83
70
|
creditsLabel={creditsLabel}
|
|
84
|
-
onPurchase={
|
|
85
|
-
onRestore={
|
|
71
|
+
onPurchase={performPurchase}
|
|
72
|
+
onRestore={performRestore}
|
|
86
73
|
trialEligibility={trialEligibility}
|
|
87
74
|
trialSubtitleText={trialConfig?.enabled ? trialConfig.trialText : undefined}
|
|
75
|
+
onPurchaseSuccess={onPurchaseSuccess}
|
|
76
|
+
onPurchaseError={onPurchaseError}
|
|
77
|
+
onAuthRequired={onAuthRequired}
|
|
78
|
+
source={purchaseSource}
|
|
88
79
|
/>
|
|
89
80
|
);
|
|
90
81
|
};
|
|
@@ -11,10 +11,19 @@ import { usePaywallActions } from "../hooks/usePaywallActions";
|
|
|
11
11
|
import { PaywallModalProps } from "./PaywallModal.types";
|
|
12
12
|
|
|
13
13
|
export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
14
|
-
const { visible, onClose, translations, packages = [], features = [], legalUrls = {}, bestValueIdentifier, creditAmounts, creditsLabel, heroImage, onPurchase, onRestore, trialEligibility = {}, trialSubtitleText } = props;
|
|
14
|
+
const { visible, onClose, translations, packages = [], features = [], legalUrls = {}, bestValueIdentifier, creditAmounts, creditsLabel, heroImage, onPurchase, onRestore, trialEligibility = {}, trialSubtitleText, onPurchaseSuccess, onPurchaseError, onAuthRequired, source } = props;
|
|
15
15
|
const tokens = useAppDesignTokens();
|
|
16
16
|
const insets = useSafeAreaInsets();
|
|
17
|
-
const { selectedPlanId, setSelectedPlanId, isProcessing, handlePurchase, handleRestore, resetState } = usePaywallActions({
|
|
17
|
+
const { selectedPlanId, setSelectedPlanId, isProcessing, handlePurchase, handleRestore, resetState } = usePaywallActions({
|
|
18
|
+
packages,
|
|
19
|
+
onPurchase,
|
|
20
|
+
onRestore,
|
|
21
|
+
source,
|
|
22
|
+
onPurchaseSuccess,
|
|
23
|
+
onPurchaseError,
|
|
24
|
+
onAuthRequired,
|
|
25
|
+
onClose
|
|
26
|
+
});
|
|
18
27
|
|
|
19
28
|
useEffect(() => {
|
|
20
29
|
if (!visible) resetState();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ImageSourcePropType } from "react-native";
|
|
2
2
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
3
3
|
import type { SubscriptionFeature, PaywallTranslations, PaywallLegalUrls } from "../entities/types";
|
|
4
|
+
import type { PurchaseSource } from "../../subscription/core/SubscriptionConstants";
|
|
4
5
|
|
|
5
6
|
export interface TrialEligibilityInfo {
|
|
6
7
|
eligible: boolean;
|
|
@@ -22,4 +23,8 @@ export interface PaywallModalProps {
|
|
|
22
23
|
onRestore?: () => Promise<void | boolean>;
|
|
23
24
|
trialEligibility?: Record<string, TrialEligibilityInfo>;
|
|
24
25
|
trialSubtitleText?: string;
|
|
26
|
+
onPurchaseSuccess?: () => void;
|
|
27
|
+
onPurchaseError?: (error: Error | string) => void;
|
|
28
|
+
onAuthRequired?: () => void;
|
|
29
|
+
source?: PurchaseSource;
|
|
25
30
|
}
|
|
@@ -52,37 +52,21 @@ export function usePaywallActions({
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
const handlePurchase = useCallback(async () => {
|
|
55
|
-
|
|
56
|
-
selectedPlanId
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const planId = selectedPlanId || (packages.length > 0 ? packages[0]?.product.identifier : null);
|
|
63
|
-
|
|
64
|
-
if (!planId || !onPurchaseRef.current || isProcessing) {
|
|
65
|
-
console.log('⚠️ [usePaywallActions] Purchase blocked', {
|
|
66
|
-
noPlanId: !planId,
|
|
67
|
-
noCallback: !onPurchaseRef.current,
|
|
68
|
-
isProcessing
|
|
69
|
-
});
|
|
70
|
-
if (!planId && onAuthRequiredRef.current) onAuthRequiredRef.current();
|
|
71
|
-
return;
|
|
55
|
+
if (!selectedPlanId || !onPurchaseRef.current || isProcessing) {
|
|
56
|
+
if (!selectedPlanId && onAuthRequiredRef.current) {
|
|
57
|
+
onAuthRequiredRef.current();
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
72
60
|
}
|
|
73
61
|
|
|
74
|
-
console.log('🟢 [usePaywallActions] Starting purchase', { planId });
|
|
75
62
|
setIsLocalProcessing(true);
|
|
76
|
-
startPurchase(
|
|
63
|
+
startPurchase(selectedPlanId, "manual");
|
|
77
64
|
|
|
78
65
|
try {
|
|
79
|
-
const pkg = packages.find((p) => p.product.identifier ===
|
|
80
|
-
console.log('📦 [usePaywallActions] Package found:', !!pkg);
|
|
66
|
+
const pkg = packages.find((p) => p.product.identifier === selectedPlanId);
|
|
81
67
|
|
|
82
68
|
if (pkg) {
|
|
83
|
-
console.log('🚀 [usePaywallActions] Calling onPurchase callback');
|
|
84
69
|
const success = await onPurchaseRef.current(pkg);
|
|
85
|
-
console.log('✅ [usePaywallActions] onPurchase completed', { success });
|
|
86
70
|
|
|
87
71
|
if (success !== false) {
|
|
88
72
|
onPurchaseSuccessRef.current?.();
|
|
@@ -90,13 +74,11 @@ export function usePaywallActions({
|
|
|
90
74
|
}
|
|
91
75
|
}
|
|
92
76
|
} catch (error) {
|
|
93
|
-
console.error('❌ [usePaywallActions] Purchase error:', error);
|
|
94
77
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
95
78
|
onPurchaseErrorRef.current?.(err);
|
|
96
79
|
} finally {
|
|
97
|
-
console.log('🏁 [usePaywallActions] Purchase flow finished');
|
|
98
80
|
setIsLocalProcessing(false);
|
|
99
|
-
endPurchase(
|
|
81
|
+
endPurchase(selectedPlanId);
|
|
100
82
|
}
|
|
101
83
|
}, [selectedPlanId, packages, isProcessing, startPurchase, endPurchase]);
|
|
102
84
|
|
|
@@ -24,14 +24,7 @@ export class PackageHandler {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async purchase(pkg: PurchasesPackage, userId: string): Promise<boolean> {
|
|
27
|
-
console.log('🔵 [PackageHandler] purchase called', {
|
|
28
|
-
productId: pkg.product.identifier,
|
|
29
|
-
userId
|
|
30
|
-
});
|
|
31
|
-
|
|
32
27
|
const result = await executePurchase(this.service, pkg, userId);
|
|
33
|
-
console.log('✅ [PackageHandler] purchase completed', { result });
|
|
34
|
-
|
|
35
28
|
return result;
|
|
36
29
|
}
|
|
37
30
|
|
|
@@ -3,8 +3,6 @@ import { getPremiumEntitlement } from "../../../revenuecat/core/types";
|
|
|
3
3
|
import { toDate } from "../../../../shared/utils/dateConverter";
|
|
4
4
|
import { detectPackageType } from "../../../../utils/packageTypeDetector";
|
|
5
5
|
|
|
6
|
-
declare const __DEV__: boolean;
|
|
7
|
-
|
|
8
6
|
export interface PremiumStatus {
|
|
9
7
|
isPremium: boolean;
|
|
10
8
|
expirationDate: Date | null;
|
|
@@ -29,11 +27,6 @@ export class PurchaseStatusResolver {
|
|
|
29
27
|
const productIdentifier = entitlement.productIdentifier ?? null;
|
|
30
28
|
const detectedPackageType = productIdentifier ? detectPackageType(productIdentifier) : null;
|
|
31
29
|
|
|
32
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
33
|
-
console.log("[PurchaseStatusResolver] productIdentifier:", productIdentifier);
|
|
34
|
-
console.log("[PurchaseStatusResolver] detectedPackageType:", detectedPackageType);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
30
|
return {
|
|
38
31
|
isPremium: true,
|
|
39
32
|
expirationDate: toDate(entitlement.expirationDate),
|
package/src/domains/subscription/infrastructure/handlers/package-operations/PackagePurchaser.ts
CHANGED
|
@@ -6,20 +6,10 @@ export async function executePurchase(
|
|
|
6
6
|
pkg: PurchasesPackage,
|
|
7
7
|
userId: string
|
|
8
8
|
): Promise<boolean> {
|
|
9
|
-
console.log('🔵 [executePurchase] Starting', {
|
|
10
|
-
productId: pkg.product.identifier,
|
|
11
|
-
userId,
|
|
12
|
-
isInitialized: service.isInitialized()
|
|
13
|
-
});
|
|
14
|
-
|
|
15
9
|
if (!service.isInitialized()) {
|
|
16
|
-
console.error('❌ [executePurchase] Service not initialized!');
|
|
17
10
|
throw new Error("Service not initialized");
|
|
18
11
|
}
|
|
19
12
|
|
|
20
|
-
console.log('🚀 [executePurchase] Calling service.purchasePackage');
|
|
21
13
|
const result = await service.purchasePackage(pkg, userId);
|
|
22
|
-
console.log('✅ [executePurchase] Completed', { success: result.success });
|
|
23
|
-
|
|
24
14
|
return result.success;
|
|
25
15
|
}
|
|
@@ -87,19 +87,9 @@ class SubscriptionManagerImpl {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
async purchasePackage(pkg: PurchasesPackage): Promise<boolean> {
|
|
90
|
-
console.log('🔵 [SubscriptionManager] purchasePackage called', {
|
|
91
|
-
productId: pkg.product.identifier,
|
|
92
|
-
isConfigured: !!this.managerConfig,
|
|
93
|
-
hasPackageHandler: !!this.packageHandler
|
|
94
|
-
});
|
|
95
|
-
|
|
96
90
|
this.ensureConfigured();
|
|
97
91
|
this.ensurePackageHandlerInitialized();
|
|
98
|
-
|
|
99
|
-
console.log('🚀 [SubscriptionManager] Calling purchasePackageOperation');
|
|
100
92
|
const result = await purchasePackageOperation(pkg, this.managerConfig, this.state, this.packageHandler!);
|
|
101
|
-
console.log('✅ [SubscriptionManager] purchasePackageOperation completed', { result });
|
|
102
|
-
|
|
103
93
|
return result;
|
|
104
94
|
}
|
|
105
95
|
|
|
@@ -22,17 +22,9 @@ export const purchasePackageOperation = async (
|
|
|
22
22
|
state: SubscriptionInternalState,
|
|
23
23
|
packageHandler: PackageHandler
|
|
24
24
|
): Promise<boolean> => {
|
|
25
|
-
console.log('🔵 [purchasePackageOperation] Starting', {
|
|
26
|
-
productId: pkg.product.identifier
|
|
27
|
-
});
|
|
28
|
-
|
|
29
25
|
ensureConfigured(managerConfig);
|
|
30
26
|
const userId = getCurrentUserIdOrThrow(state);
|
|
31
|
-
|
|
32
|
-
console.log('🚀 [purchasePackageOperation] Calling packageHandler.purchase', { userId });
|
|
33
27
|
const result = await packageHandler.purchase(pkg, userId);
|
|
34
|
-
console.log('✅ [purchasePackageOperation] Completed', { result });
|
|
35
|
-
|
|
36
28
|
return result;
|
|
37
29
|
};
|
|
38
30
|
|
|
@@ -16,38 +16,23 @@ export async function handlePurchase(
|
|
|
16
16
|
pkg: PurchasesPackage,
|
|
17
17
|
userId: string
|
|
18
18
|
): Promise<PurchaseResult> {
|
|
19
|
-
console.log('🔵 [PurchaseHandler] handlePurchase called', {
|
|
20
|
-
productId: pkg.product.identifier,
|
|
21
|
-
userId,
|
|
22
|
-
isInitialized: deps.isInitialized()
|
|
23
|
-
});
|
|
24
|
-
|
|
25
19
|
validatePurchaseReady(deps.isInitialized());
|
|
26
20
|
|
|
27
21
|
const consumableIds = deps.config.consumableProductIdentifiers || [];
|
|
28
22
|
const isConsumable = isConsumableProduct(pkg, consumableIds);
|
|
29
23
|
|
|
30
|
-
console.log('📦 [PurchaseHandler] Product type', { isConsumable });
|
|
31
|
-
|
|
32
24
|
try {
|
|
33
|
-
console.log('🚀 [PurchaseHandler] Calling executePurchase');
|
|
34
25
|
const result = await executePurchase(deps.config, userId, pkg, isConsumable);
|
|
35
|
-
console.log('✅ [PurchaseHandler] executePurchase completed', { success: result.success });
|
|
36
26
|
return result;
|
|
37
27
|
} catch (error) {
|
|
38
|
-
console.error('❌ [PurchaseHandler] Purchase failed', { error });
|
|
39
|
-
|
|
40
28
|
if (isUserCancelledError(error)) {
|
|
41
|
-
console.log('⚠️ [PurchaseHandler] User cancelled');
|
|
42
29
|
return { success: false, isPremium: false, productId: pkg.product.identifier };
|
|
43
30
|
}
|
|
44
31
|
|
|
45
32
|
if (isAlreadyPurchasedError(error)) {
|
|
46
|
-
console.log('⚠️ [PurchaseHandler] Already purchased');
|
|
47
33
|
return await handleAlreadyPurchasedError(deps, userId, pkg, error);
|
|
48
34
|
}
|
|
49
35
|
|
|
50
|
-
console.error('❌ [PurchaseHandler] Unhandled error');
|
|
51
36
|
return handlePurchaseError(error, pkg, userId);
|
|
52
37
|
}
|
|
53
38
|
}
|
|
@@ -60,15 +60,7 @@ export class RevenueCatService implements IRevenueCatService {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
async purchasePackage(pkg: PurchasesPackage, userId: string): Promise<PurchaseResult> {
|
|
63
|
-
console.log('🔵 [RevenueCatService] purchasePackage called', {
|
|
64
|
-
productId: pkg.product.identifier,
|
|
65
|
-
userId,
|
|
66
|
-
isInitialized: this.isInitialized()
|
|
67
|
-
});
|
|
68
|
-
|
|
69
63
|
const result = await handlePurchase(this.getSDKParams(), pkg, userId);
|
|
70
|
-
console.log('✅ [RevenueCatService] purchasePackage completed', { success: result.success });
|
|
71
|
-
|
|
72
64
|
return result;
|
|
73
65
|
}
|
|
74
66
|
|
|
@@ -77,26 +77,15 @@ export async function executePurchase(
|
|
|
77
77
|
pkg: PurchasesPackage,
|
|
78
78
|
isConsumable: boolean
|
|
79
79
|
): Promise<PurchaseResult> {
|
|
80
|
-
console.log('🔵 [PurchaseExecutor] executePurchase called', {
|
|
81
|
-
productId: pkg.product.identifier,
|
|
82
|
-
userId,
|
|
83
|
-
isConsumable,
|
|
84
|
-
packageType: pkg.packageType
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
console.log('🚀 [PurchaseExecutor] Calling Purchases.purchasePackage (RevenueCat SDK)');
|
|
88
80
|
const { customerInfo } = await Purchases.purchasePackage(pkg);
|
|
89
|
-
console.log('✅ [PurchaseExecutor] Purchases.purchasePackage completed');
|
|
90
81
|
|
|
91
82
|
const productId = pkg.product.identifier;
|
|
92
83
|
const packageType = pkg.packageType ?? null;
|
|
93
84
|
|
|
94
85
|
if (isConsumable) {
|
|
95
|
-
console.log('💰 [PurchaseExecutor] Processing as consumable purchase');
|
|
96
86
|
return executeConsumablePurchase(config, userId, productId, customerInfo, packageType);
|
|
97
87
|
}
|
|
98
88
|
|
|
99
|
-
console.log('📅 [PurchaseExecutor] Processing as subscription purchase');
|
|
100
89
|
return executeSubscriptionPurchase(
|
|
101
90
|
config,
|
|
102
91
|
userId,
|
package/src/domains/subscription/presentation/screens/components/SubscriptionHeaderContent.tsx
CHANGED
|
@@ -4,8 +4,6 @@ import { DetailRow } from "../../components/details/DetailRow";
|
|
|
4
4
|
import type { SubscriptionHeaderProps } from "./SubscriptionHeader.types";
|
|
5
5
|
import { formatPackageTypeForDisplay } from "../../../../subscription/utils/packageTypeFormatter";
|
|
6
6
|
|
|
7
|
-
declare const __DEV__: boolean;
|
|
8
|
-
|
|
9
7
|
interface SubscriptionHeaderContentProps {
|
|
10
8
|
isLifetime: boolean;
|
|
11
9
|
showExpirationDate: boolean;
|
|
@@ -40,14 +38,8 @@ export const SubscriptionHeaderContent: React.FC<SubscriptionHeaderContentProps>
|
|
|
40
38
|
latestPurchaseDate,
|
|
41
39
|
billingIssuesDetected,
|
|
42
40
|
isSandbox,
|
|
43
|
-
}) =>
|
|
44
|
-
|
|
45
|
-
console.log('[SubscriptionHeaderContent] packageType:', packageType);
|
|
46
|
-
console.log('[SubscriptionHeaderContent] periodType:', periodType);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<View style={styles.details}>
|
|
41
|
+
}) => (
|
|
42
|
+
<View style={styles.details}>
|
|
51
43
|
{isLifetime ? (
|
|
52
44
|
<DetailRow
|
|
53
45
|
label={translations.statusLabel}
|
|
@@ -145,5 +137,4 @@ export const SubscriptionHeaderContent: React.FC<SubscriptionHeaderContentProps>
|
|
|
145
137
|
</>
|
|
146
138
|
)}
|
|
147
139
|
</View>
|
|
148
|
-
|
|
149
|
-
};
|
|
140
|
+
);
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package Type Detector Tests
|
|
3
|
-
* Test various product ID patterns
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { detectPackageType } from "./packageTypeDetector";
|
|
7
|
-
import { PACKAGE_TYPE } from "../domains/subscription/core/SubscriptionConstants";
|
|
8
|
-
|
|
9
|
-
// Test common product ID patterns
|
|
10
|
-
const testCases = [
|
|
11
|
-
// Standard patterns
|
|
12
|
-
{ id: "com.umituz.aibabyfacepredictor.weekly", expected: PACKAGE_TYPE.WEEKLY },
|
|
13
|
-
{ id: "com.umituz.aibabyfacepredictor.monthly", expected: PACKAGE_TYPE.MONTHLY },
|
|
14
|
-
{ id: "com.umituz.aibabyfacepredictor.yearly", expected: PACKAGE_TYPE.YEARLY },
|
|
15
|
-
|
|
16
|
-
// Test store patterns
|
|
17
|
-
{ id: "com.umituz.aibabyfacepredictor.test.weekly", expected: PACKAGE_TYPE.WEEKLY },
|
|
18
|
-
{ id: "com.umituz.aibabyfacepredictor.test.monthly", expected: PACKAGE_TYPE.MONTHLY },
|
|
19
|
-
{ id: "com.umituz.aibabyfacepredictor.test.yearly", expected: PACKAGE_TYPE.YEARLY },
|
|
20
|
-
|
|
21
|
-
// Alternative naming
|
|
22
|
-
{ id: "weekly_subscription", expected: PACKAGE_TYPE.WEEKLY },
|
|
23
|
-
{ id: "monthly_subscription", expected: PACKAGE_TYPE.MONTHLY },
|
|
24
|
-
{ id: "annual_subscription", expected: PACKAGE_TYPE.YEARLY },
|
|
25
|
-
|
|
26
|
-
// Edge cases
|
|
27
|
-
{ id: "week_pass", expected: PACKAGE_TYPE.WEEKLY },
|
|
28
|
-
{ id: "month_pass", expected: PACKAGE_TYPE.MONTHLY },
|
|
29
|
-
{ id: "year_pass", expected: PACKAGE_TYPE.YEARLY },
|
|
30
|
-
|
|
31
|
-
// Should NOT match
|
|
32
|
-
{ id: "credit_package", expected: PACKAGE_TYPE.UNKNOWN },
|
|
33
|
-
{ id: "random_product", expected: PACKAGE_TYPE.UNKNOWN },
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
console.log("=== Package Type Detector Tests ===\n");
|
|
37
|
-
|
|
38
|
-
let passed = 0;
|
|
39
|
-
let failed = 0;
|
|
40
|
-
|
|
41
|
-
testCases.forEach(({ id, expected }) => {
|
|
42
|
-
const result = detectPackageType(id);
|
|
43
|
-
const isPass = result === expected;
|
|
44
|
-
|
|
45
|
-
if (isPass) {
|
|
46
|
-
passed++;
|
|
47
|
-
console.log(`✅ PASS: "${id}" → ${result}`);
|
|
48
|
-
} else {
|
|
49
|
-
failed++;
|
|
50
|
-
console.log(`❌ FAIL: "${id}" → ${result} (expected: ${expected})`);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
console.log(`\n=== Results: ${passed} passed, ${failed} failed ===`);
|
|
55
|
-
|
|
56
|
-
// Test actual RevenueCat product IDs (if available)
|
|
57
|
-
console.log("\n=== Test Your Actual Product IDs ===");
|
|
58
|
-
console.log("Add your actual product IDs below to test:\n");
|
|
59
|
-
|
|
60
|
-
const yourProductIds = [
|
|
61
|
-
// Add your actual product IDs here
|
|
62
|
-
// "com.yourapp.yourproduct.weekly",
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
if (yourProductIds.length > 0) {
|
|
66
|
-
yourProductIds.forEach(id => {
|
|
67
|
-
const result = detectPackageType(id);
|
|
68
|
-
console.log(`Product: "${id}" → Detected as: ${result}`);
|
|
69
|
-
});
|
|
70
|
-
}
|