@umituz/react-native-subscription 2.27.43 → 2.27.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/domains/paywall/components/PaywallContainer.tsx +13 -0
- package/src/domains/paywall/components/PaywallContainer.types.ts +7 -1
- package/src/domains/paywall/components/PaywallModal.tsx +7 -1
- package/src/domains/paywall/components/PlanCard.tsx +12 -1
- package/src/utils/creditMapper.ts +29 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.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",
|
|
@@ -8,6 +8,7 @@ import React, { useMemo, useEffect } from "react";
|
|
|
8
8
|
import { usePaywallVisibility } from "../../../presentation/hooks/usePaywallVisibility";
|
|
9
9
|
import { useSubscriptionPackages } from "../../../revenuecat/presentation/hooks/useSubscriptionPackages";
|
|
10
10
|
import { useRevenueCatTrialEligibility } from "../../../revenuecat/presentation/hooks/useRevenueCatTrialEligibility";
|
|
11
|
+
import { createCreditAmountsFromPackages } from "../../../utils/creditMapper";
|
|
11
12
|
import { PaywallModal, type TrialEligibilityInfo } from "./PaywallModal";
|
|
12
13
|
import { usePaywallActions } from "../hooks/usePaywallActions";
|
|
13
14
|
import type { PaywallContainerProps } from "./PaywallContainer.types";
|
|
@@ -19,6 +20,9 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
19
20
|
features,
|
|
20
21
|
heroImage,
|
|
21
22
|
bestValueIdentifier,
|
|
23
|
+
creditAmounts: providedCreditAmounts,
|
|
24
|
+
creditsLabel,
|
|
25
|
+
packageAllocations,
|
|
22
26
|
source,
|
|
23
27
|
onPurchaseSuccess,
|
|
24
28
|
onPurchaseError,
|
|
@@ -85,6 +89,13 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
85
89
|
return result;
|
|
86
90
|
}, [eligibilityMap, trialConfig?.enabled, trialConfig?.durationDays]);
|
|
87
91
|
|
|
92
|
+
// Compute credit amounts from packageAllocations if not provided directly
|
|
93
|
+
const creditAmounts = useMemo(() => {
|
|
94
|
+
if (providedCreditAmounts) return providedCreditAmounts;
|
|
95
|
+
if (!packageAllocations || packages.length === 0) return undefined;
|
|
96
|
+
return createCreditAmountsFromPackages(packages, packageAllocations);
|
|
97
|
+
}, [providedCreditAmounts, packageAllocations, packages]);
|
|
98
|
+
|
|
88
99
|
if (!isVisible) return null;
|
|
89
100
|
|
|
90
101
|
return (
|
|
@@ -98,6 +109,8 @@ export const PaywallContainer: React.FC<PaywallContainerProps> = (props) => {
|
|
|
98
109
|
features={features ? [...features] : undefined}
|
|
99
110
|
heroImage={heroImage}
|
|
100
111
|
bestValueIdentifier={bestValueIdentifier}
|
|
112
|
+
creditAmounts={creditAmounts}
|
|
113
|
+
creditsLabel={creditsLabel}
|
|
101
114
|
onPurchase={handlePurchase}
|
|
102
115
|
onRestore={handleRestore}
|
|
103
116
|
trialEligibility={trialEligibility}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { ImageSourcePropType } from "react-native";
|
|
7
7
|
import type { PaywallTranslations, PaywallLegalUrls, SubscriptionFeature } from "../entities";
|
|
8
|
-
import type { PurchaseSource } from "../../../domain/entities/Credits";
|
|
8
|
+
import type { PurchaseSource, PackageAllocationMap } from "../../../domain/entities/Credits";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Trial display configuration
|
|
@@ -33,6 +33,12 @@ export interface PaywallContainerProps {
|
|
|
33
33
|
readonly heroImage?: ImageSourcePropType;
|
|
34
34
|
/** Best value package identifier for badge */
|
|
35
35
|
readonly bestValueIdentifier?: string;
|
|
36
|
+
/** Credit amounts per product identifier (takes precedence over packageAllocations) */
|
|
37
|
+
readonly creditAmounts?: Record<string, number>;
|
|
38
|
+
/** Credits label text (e.g., "credits") */
|
|
39
|
+
readonly creditsLabel?: string;
|
|
40
|
+
/** Package allocations for auto-computing creditAmounts (used when creditAmounts not provided) */
|
|
41
|
+
readonly packageAllocations?: PackageAllocationMap;
|
|
36
42
|
/** Source of the paywall - affects pending purchase handling */
|
|
37
43
|
readonly source?: PurchaseSource;
|
|
38
44
|
/** Callback when purchase succeeds */
|
|
@@ -33,6 +33,10 @@ export interface PaywallModalProps {
|
|
|
33
33
|
isLoading?: boolean;
|
|
34
34
|
legalUrls?: PaywallLegalUrls;
|
|
35
35
|
bestValueIdentifier?: string;
|
|
36
|
+
/** Credit amounts per product identifier */
|
|
37
|
+
creditAmounts?: Record<string, number>;
|
|
38
|
+
/** Credits label text (e.g., "credits") */
|
|
39
|
+
creditsLabel?: string;
|
|
36
40
|
heroImage?: ImageSourcePropType;
|
|
37
41
|
onPurchase?: (pkg: PurchasesPackage) => Promise<void | boolean>;
|
|
38
42
|
onRestore?: () => Promise<void | boolean>;
|
|
@@ -43,7 +47,7 @@ export interface PaywallModalProps {
|
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
46
|
-
const { visible, onClose, translations, packages = [], features = [], isLoading = false, legalUrls = {}, bestValueIdentifier, heroImage, onPurchase, onRestore, trialEligibility = {}, trialSubtitleText } = props;
|
|
50
|
+
const { visible, onClose, translations, packages = [], features = [], isLoading = false, legalUrls = {}, bestValueIdentifier, creditAmounts, creditsLabel, heroImage, onPurchase, onRestore, trialEligibility = {}, trialSubtitleText } = props;
|
|
47
51
|
const tokens = useAppDesignTokens();
|
|
48
52
|
const [selectedPlanId, setSelectedPlanId] = useState<string | null>(null);
|
|
49
53
|
const [isLocalProcessing, setIsLocalProcessing] = useState(false);
|
|
@@ -150,6 +154,8 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
150
154
|
isSelected={selectedPlanId === productId}
|
|
151
155
|
onSelect={() => setSelectedPlanId(productId)}
|
|
152
156
|
badge={productId === bestValueIdentifier ? translations.bestValueBadgeText : undefined}
|
|
157
|
+
creditAmount={creditAmounts?.[productId]}
|
|
158
|
+
creditsLabel={creditsLabel}
|
|
153
159
|
hasFreeTrial={hasFreeTrial}
|
|
154
160
|
trialSubtitleText={hasFreeTrial ? trialSubtitleText : undefined}
|
|
155
161
|
/>
|
|
@@ -21,6 +21,10 @@ interface PlanCardProps {
|
|
|
21
21
|
onSelect: () => void;
|
|
22
22
|
/** Badge text (e.g., "Best Value") - NOT for trial */
|
|
23
23
|
badge?: string;
|
|
24
|
+
/** Credit amount for this plan */
|
|
25
|
+
creditAmount?: number;
|
|
26
|
+
/** Credits label text (e.g., "credits") */
|
|
27
|
+
creditsLabel?: string;
|
|
24
28
|
/** Whether this plan has a free trial (Apple-compliant display) */
|
|
25
29
|
hasFreeTrial?: boolean;
|
|
26
30
|
/** Trial subtitle text (e.g., "7 days free, then billed") - shown as small gray text */
|
|
@@ -28,7 +32,7 @@ interface PlanCardProps {
|
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export const PlanCard: React.FC<PlanCardProps> = React.memo(
|
|
31
|
-
({ pkg, isSelected, onSelect, badge, hasFreeTrial, trialSubtitleText }) => {
|
|
35
|
+
({ pkg, isSelected, onSelect, badge, creditAmount, creditsLabel, hasFreeTrial, trialSubtitleText }) => {
|
|
32
36
|
const tokens = useAppDesignTokens();
|
|
33
37
|
const title = pkg.product.title;
|
|
34
38
|
const price = formatPriceWithPeriod(pkg.product.price, pkg.product.currencyCode, pkg.identifier);
|
|
@@ -73,6 +77,13 @@ export const PlanCard: React.FC<PlanCardProps> = React.memo(
|
|
|
73
77
|
{title}
|
|
74
78
|
</AtomicText>
|
|
75
79
|
|
|
80
|
+
{/* Credits info */}
|
|
81
|
+
{creditAmount && creditsLabel && (
|
|
82
|
+
<AtomicText type="bodySmall" style={{ color: tokens.colors.textSecondary }}>
|
|
83
|
+
{creditAmount} {creditsLabel}
|
|
84
|
+
</AtomicText>
|
|
85
|
+
)}
|
|
86
|
+
|
|
76
87
|
{/* Trial info - Apple-compliant: small, gray, subordinate */}
|
|
77
88
|
{hasFreeTrial && trialSubtitleText && (
|
|
78
89
|
<AtomicText
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { detectPackageType, type SubscriptionPackageType } from "./packageTypeDetector";
|
|
2
2
|
import type { PackageAllocationMap } from "../domain/entities/Credits";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -11,3 +11,31 @@ export function getCreditAllocation(
|
|
|
11
11
|
if (packageType === "unknown" || !allocations) return null;
|
|
12
12
|
return allocations[packageType]?.credits ?? null;
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create credit amounts mapping for PaywallModal from RevenueCat packages
|
|
17
|
+
* Maps product.identifier to credit amount using dynamic allocations
|
|
18
|
+
*/
|
|
19
|
+
export function createCreditAmountsFromPackages(
|
|
20
|
+
packages: Array<{ product: { identifier: string } }>,
|
|
21
|
+
allocations?: PackageAllocationMap
|
|
22
|
+
): Record<string, number> {
|
|
23
|
+
const result: Record<string, number> = {};
|
|
24
|
+
|
|
25
|
+
if (!allocations) return result;
|
|
26
|
+
|
|
27
|
+
for (const pkg of packages) {
|
|
28
|
+
const identifier = pkg?.product?.identifier;
|
|
29
|
+
|
|
30
|
+
if (!identifier) continue;
|
|
31
|
+
|
|
32
|
+
const packageType = detectPackageType(identifier);
|
|
33
|
+
const credits = getCreditAllocation(packageType, allocations);
|
|
34
|
+
|
|
35
|
+
if (credits !== null) {
|
|
36
|
+
result[identifier] = credits;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return result;
|
|
41
|
+
}
|