@umituz/react-native-subscription 2.2.38 → 2.2.40
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 +3 -2
- package/src/application/ports/ISubscriptionRepository.ts +13 -0
- package/src/domain/entities/SubscriptionStatus.ts +38 -0
- package/src/domain/value-objects/SubscriptionConfig.ts +15 -0
- package/src/index.ts +5 -42
- package/src/presentation/components/details/PremiumStatusBadge.tsx +5 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.40",
|
|
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",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@tanstack/react-query": ">=5.0.0",
|
|
31
|
+
"@umituz/react-native-design-system": "latest",
|
|
31
32
|
"@umituz/react-native-firestore": "*",
|
|
32
33
|
"@umituz/react-native-legal": "*",
|
|
33
34
|
"expo-constants": ">=18.0.0",
|
|
@@ -59,4 +60,4 @@
|
|
|
59
60
|
"README.md",
|
|
60
61
|
"LICENSE"
|
|
61
62
|
]
|
|
62
|
-
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ISubscriptionRepository Interface
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { SubscriptionStatus } from '../../domain/entities/SubscriptionStatus';
|
|
6
|
+
|
|
7
|
+
export interface ISubscriptionRepository {
|
|
8
|
+
getSubscriptionStatus(userId: string): Promise<SubscriptionStatus | null>;
|
|
9
|
+
saveSubscriptionStatus(userId: string, status: SubscriptionStatus): Promise<void>;
|
|
10
|
+
updateSubscriptionStatus(userId: string, status: Partial<SubscriptionStatus>): Promise<SubscriptionStatus>;
|
|
11
|
+
syncSubscription(userId: string): Promise<SubscriptionStatus>;
|
|
12
|
+
isSubscriptionValid(status: SubscriptionStatus): boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription Status Entity
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type SubscriptionStatusType = 'active' | 'expired' | 'canceled' | 'none';
|
|
6
|
+
|
|
7
|
+
export interface SubscriptionStatus {
|
|
8
|
+
isPremium: boolean;
|
|
9
|
+
expiresAt: string | null;
|
|
10
|
+
productId: string | null;
|
|
11
|
+
purchasedAt?: string | null;
|
|
12
|
+
customerId?: string | null;
|
|
13
|
+
syncedAt?: string | null;
|
|
14
|
+
status?: SubscriptionStatusType;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const createDefaultSubscriptionStatus = (): SubscriptionStatus => ({
|
|
18
|
+
isPremium: false,
|
|
19
|
+
expiresAt: null,
|
|
20
|
+
productId: null,
|
|
21
|
+
purchasedAt: null,
|
|
22
|
+
customerId: null,
|
|
23
|
+
syncedAt: null,
|
|
24
|
+
status: 'none',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const isSubscriptionValid = (status: SubscriptionStatus | null): boolean => {
|
|
28
|
+
if (!status || !status.isPremium) return false;
|
|
29
|
+
|
|
30
|
+
if (!status.expiresAt) return true; // Lifetime
|
|
31
|
+
|
|
32
|
+
const expirationDate = new Date(status.expiresAt);
|
|
33
|
+
const now = new Date();
|
|
34
|
+
|
|
35
|
+
// Add 24-hour grace period buffer
|
|
36
|
+
const buffer = 24 * 60 * 60 * 1000;
|
|
37
|
+
return expirationDate.getTime() + buffer > now.getTime();
|
|
38
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription Config Value Object
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ISubscriptionRepository } from "../../application/ports/ISubscriptionRepository";
|
|
6
|
+
import { SubscriptionStatus } from "../entities/SubscriptionStatus";
|
|
7
|
+
|
|
8
|
+
export interface SubscriptionConfig {
|
|
9
|
+
repository: ISubscriptionRepository;
|
|
10
|
+
revenueCatApiKey?: string;
|
|
11
|
+
entitlements?: string[];
|
|
12
|
+
debugMode?: boolean;
|
|
13
|
+
onStatusChanged?: (userId: string, status: SubscriptionStatus) => Promise<void> | void;
|
|
14
|
+
onError?: (error: Error, context: string) => Promise<void> | void;
|
|
15
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -13,30 +13,19 @@
|
|
|
13
13
|
// BROKEN EXPORTS - Files missing
|
|
14
14
|
// =============================================================================
|
|
15
15
|
|
|
16
|
-
/*
|
|
17
|
-
export {
|
|
18
|
-
SubscriptionError,
|
|
19
|
-
SubscriptionRepositoryError,
|
|
20
|
-
SubscriptionValidationError,
|
|
21
|
-
SubscriptionConfigurationError,
|
|
22
|
-
} from "./domain/errors/SubscriptionError";
|
|
23
|
-
|
|
24
16
|
export {
|
|
25
17
|
createDefaultSubscriptionStatus,
|
|
26
18
|
isSubscriptionValid,
|
|
27
19
|
} from "./domain/entities/SubscriptionStatus";
|
|
28
|
-
export type { SubscriptionStatus } from "./domain/entities/SubscriptionStatus";
|
|
20
|
+
export type { SubscriptionStatus, SubscriptionStatusType } from "./domain/entities/SubscriptionStatus";
|
|
29
21
|
|
|
30
22
|
export type { SubscriptionConfig } from "./domain/value-objects/SubscriptionConfig";
|
|
31
23
|
|
|
32
24
|
export type { ISubscriptionRepository } from "./application/ports/ISubscriptionRepository";
|
|
33
|
-
export type { ISubscriptionService } from "./application/ports/ISubscriptionService";
|
|
34
25
|
|
|
35
26
|
export {
|
|
36
27
|
SubscriptionService,
|
|
37
28
|
initializeSubscriptionService,
|
|
38
|
-
getSubscriptionService,
|
|
39
|
-
resetSubscriptionService,
|
|
40
29
|
} from "./infrastructure/services/SubscriptionService";
|
|
41
30
|
|
|
42
31
|
export { useSubscription } from "./presentation/hooks/useSubscription";
|
|
@@ -47,6 +36,10 @@ export {
|
|
|
47
36
|
type SubscriptionDetails,
|
|
48
37
|
} from "./presentation/hooks/useSubscriptionDetails";
|
|
49
38
|
|
|
39
|
+
// Feedback
|
|
40
|
+
export * from "./presentation/components/feedback/PaywallFeedbackModal";
|
|
41
|
+
export * from "./presentation/hooks/feedback/usePaywallFeedback";
|
|
42
|
+
|
|
50
43
|
export {
|
|
51
44
|
usePremiumGate,
|
|
52
45
|
type UsePremiumGateParams,
|
|
@@ -59,41 +52,12 @@ export {
|
|
|
59
52
|
type UseFeatureGateResult,
|
|
60
53
|
} from "./presentation/hooks/useFeatureGate";
|
|
61
54
|
|
|
62
|
-
export {
|
|
63
|
-
useUserTier,
|
|
64
|
-
type UseUserTierParams,
|
|
65
|
-
type UseUserTierResult,
|
|
66
|
-
} from "./presentation/hooks/useUserTier";
|
|
67
|
-
|
|
68
55
|
export {
|
|
69
56
|
useUserTierWithRepository,
|
|
70
57
|
type UseUserTierWithRepositoryParams,
|
|
71
58
|
type UseUserTierWithRepositoryResult,
|
|
72
59
|
type AuthProvider,
|
|
73
60
|
} from "./presentation/hooks/useUserTierWithRepository";
|
|
74
|
-
*/
|
|
75
|
-
|
|
76
|
-
// Feedback
|
|
77
|
-
export * from "./presentation/components/feedback/PaywallFeedbackModal";
|
|
78
|
-
export * from "./presentation/hooks/feedback/usePaywallFeedback";
|
|
79
|
-
|
|
80
|
-
export {
|
|
81
|
-
usePremiumGate,
|
|
82
|
-
type UsePremiumGateParams,
|
|
83
|
-
type UsePremiumGateResult,
|
|
84
|
-
} from "./presentation/hooks/usePremiumGate";
|
|
85
|
-
|
|
86
|
-
export {
|
|
87
|
-
useFeatureGate,
|
|
88
|
-
type UseFeatureGateParams,
|
|
89
|
-
type UseFeatureGateResult,
|
|
90
|
-
} from "./presentation/hooks/useFeatureGate";
|
|
91
|
-
|
|
92
|
-
export {
|
|
93
|
-
useUserTier,
|
|
94
|
-
type UseUserTierParams,
|
|
95
|
-
type UseUserTierResult,
|
|
96
|
-
} from "./presentation/hooks/useUserTier";
|
|
97
61
|
|
|
98
62
|
// =============================================================================
|
|
99
63
|
// PRESENTATION LAYER - Paywall Components
|
|
@@ -136,7 +100,6 @@ export {
|
|
|
136
100
|
export {
|
|
137
101
|
PremiumStatusBadge,
|
|
138
102
|
type PremiumStatusBadgeProps,
|
|
139
|
-
type SubscriptionStatusType,
|
|
140
103
|
} from "./presentation/components/details/PremiumStatusBadge";
|
|
141
104
|
|
|
142
105
|
// =============================================================================
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, Text, StyleSheet } from "react-native";
|
|
8
8
|
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
9
|
-
|
|
10
|
-
export type SubscriptionStatusType = "active" | "expired" | "none";
|
|
9
|
+
import { SubscriptionStatusType } from "../../../domain/entities/SubscriptionStatus";
|
|
11
10
|
|
|
12
11
|
export interface PremiumStatusBadgeProps {
|
|
13
12
|
status: SubscriptionStatusType;
|
|
14
13
|
activeLabel?: string;
|
|
15
14
|
expiredLabel?: string;
|
|
16
15
|
noneLabel?: string;
|
|
16
|
+
canceledLabel?: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -24,6 +24,7 @@ export const PremiumStatusBadge: React.FC<PremiumStatusBadgeProps> = ({
|
|
|
24
24
|
activeLabel = "Active",
|
|
25
25
|
expiredLabel = "Expired",
|
|
26
26
|
noneLabel = "Free",
|
|
27
|
+
canceledLabel = "Canceled",
|
|
27
28
|
}) => {
|
|
28
29
|
const tokens = useAppDesignTokens();
|
|
29
30
|
|
|
@@ -31,12 +32,14 @@ export const PremiumStatusBadge: React.FC<PremiumStatusBadgeProps> = ({
|
|
|
31
32
|
active: activeLabel,
|
|
32
33
|
expired: expiredLabel,
|
|
33
34
|
none: noneLabel,
|
|
35
|
+
canceled: canceledLabel,
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
const colors: Record<SubscriptionStatusType, string> = {
|
|
37
39
|
active: tokens.colors.success,
|
|
38
40
|
expired: tokens.colors.error,
|
|
39
41
|
none: tokens.colors.textTertiary,
|
|
42
|
+
canceled: tokens.colors.warning,
|
|
40
43
|
};
|
|
41
44
|
|
|
42
45
|
const backgroundColor = colors[status];
|