@umituz/react-native-subscription 2.27.112 → 2.27.114
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/credits/application/CreditsInitializer.ts +28 -125
- package/src/domains/credits/application/credit-strategies/{CreditAllocationContext.ts → CreditAllocationOrchestrator.ts} +4 -9
- package/src/domains/credits/application/creditDocumentHelpers.ts +58 -0
- package/src/domains/credits/application/creditOperationUtils.ts +154 -0
- package/src/domains/credits/core/CreditsMapper.ts +8 -13
- package/src/domains/credits/infrastructure/{CreditsRepositoryProvider.ts → CreditsRepositoryManager.ts} +2 -2
- package/src/domains/credits/presentation/useCredits.ts +2 -3
- package/src/domains/credits/presentation/useDeductCredit.ts +4 -4
- package/src/domains/paywall/components/PaywallContainer.types.ts +1 -1
- package/src/domains/paywall/components/PaywallModal.tsx +28 -52
- package/src/domains/paywall/hooks/usePaywallActions.ts +77 -33
- package/src/domains/subscription/application/SubscriptionInitializer.ts +1 -1
- package/src/domains/subscription/application/SubscriptionSyncService.ts +17 -21
- package/src/domains/subscription/core/RevenueCatError.ts +40 -31
- package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +0 -1
- package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +19 -85
- package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +33 -75
- package/src/domains/subscription/infrastructure/managers/subscriptionManagerUtils.ts +57 -0
- package/src/domains/subscription/infrastructure/services/CustomerInfoListenerManager.ts +3 -12
- package/src/domains/subscription/infrastructure/services/PurchaseHandler.ts +0 -2
- package/src/domains/subscription/infrastructure/services/RevenueCatInitializer.ts +2 -4
- package/src/domains/subscription/infrastructure/services/RevenueCatService.ts +1 -5
- package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +3 -12
- package/src/domains/subscription/infrastructure/utils/authPurchaseState.ts +69 -0
- package/src/domains/subscription/infrastructure/utils/trialEligibilityUtils.ts +77 -0
- package/src/domains/subscription/presentation/components/feedback/FeedbackOption.tsx +139 -0
- package/src/domains/subscription/presentation/components/feedback/PaywallFeedbackModal.tsx +15 -70
- package/src/domains/subscription/presentation/components/feedback/paywallFeedbackStyles.ts +0 -92
- package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.tsx +1 -1
- package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +1 -18
- package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +19 -69
- package/src/domains/subscription/presentation/usePaywallVisibility.ts +1 -1
- package/src/domains/subscription/presentation/usePremium.ts +2 -11
- package/src/domains/subscription/presentation/useSubscriptionStatus.ts +1 -6
- package/src/domains/trial/application/TrialService.ts +4 -8
- package/src/domains/wallet/index.ts +0 -6
- package/src/domains/wallet/infrastructure/repositories/TransactionRepository.ts +1 -1
- package/src/domains/wallet/infrastructure/services/ProductMetadataService.ts +0 -13
- package/src/domains/wallet/presentation/hooks/useProductMetadata.ts +0 -10
- package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +0 -8
- package/src/domains/wallet/presentation/screens/WalletScreen.tsx +57 -43
- package/src/index.ts +1 -1
- package/src/init/createSubscriptionInitModule.ts +1 -4
- package/src/presentation/hooks/feedback/useFeedbackSubmit.ts +0 -14
- package/src/shared/application/ActivationHandler.ts +6 -6
- package/src/shared/application/FeedbackService.ts +0 -21
- package/src/shared/infrastructure/SubscriptionEventBus.ts +1 -2
- package/src/shared/presentation/index.ts +1 -0
- package/src/shared/presentation/layouts/ScreenLayout.tsx +79 -0
- package/src/shared/types/CommonTypes.ts +65 -0
- package/src/shared/utils/BaseError.ts +26 -0
- package/src/shared/utils/Logger.ts +15 -46
- package/src/shared/utils/Result.ts +16 -0
- package/src/shared/utils/SubscriptionConfig.ts +1 -1
- package/src/shared/utils/SubscriptionError.ts +20 -30
- package/src/utils/appUtils.ts +34 -0
- package/src/utils/dateUtils.ts +32 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/packageTypeDetector.ts +0 -4
- package/src/domains/wallet/presentation/screens/WalletScreenContainer.tsx +0 -88
|
@@ -3,55 +3,45 @@
|
|
|
3
3
|
* Custom error class for subscription-related errors
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
public readonly code: string;
|
|
6
|
+
import { BaseError } from "./BaseError";
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
export class SubscriptionError extends BaseError {
|
|
9
|
+
constructor(message: string, code: string = 'SUBSCRIPTION_ERROR', cause?: Error) {
|
|
10
|
+
super(message, code, cause);
|
|
11
11
|
this.name = 'SubscriptionError';
|
|
12
|
-
this.code = code;
|
|
13
|
-
Object.setPrototypeOf(this, SubscriptionError.prototype);
|
|
14
12
|
}
|
|
15
13
|
|
|
16
|
-
static notFound(message: string = 'Subscription not found'): SubscriptionError {
|
|
17
|
-
return new SubscriptionError(message, 'SUBSCRIPTION_NOT_FOUND');
|
|
14
|
+
static notFound(message: string = 'Subscription not found', cause?: Error): SubscriptionError {
|
|
15
|
+
return new SubscriptionError(message, 'SUBSCRIPTION_NOT_FOUND', cause);
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
static expired(message: string = 'Subscription has expired'): SubscriptionError {
|
|
21
|
-
return new SubscriptionError(message, 'SUBSCRIPTION_EXPIRED');
|
|
18
|
+
static expired(message: string = 'Subscription has expired', cause?: Error): SubscriptionError {
|
|
19
|
+
return new SubscriptionError(message, 'SUBSCRIPTION_EXPIRED', cause);
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
static purchaseFailed(message: string = 'Purchase failed'): SubscriptionError {
|
|
25
|
-
return new SubscriptionError(message, 'PURCHASE_FAILED');
|
|
22
|
+
static purchaseFailed(message: string = 'Purchase failed', cause?: Error): SubscriptionError {
|
|
23
|
+
return new SubscriptionError(message, 'PURCHASE_FAILED', cause);
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
static restoreFailed(message: string = 'Restore failed'): SubscriptionError {
|
|
29
|
-
return new SubscriptionError(message, 'RESTORE_FAILED');
|
|
26
|
+
static restoreFailed(message: string = 'Restore failed', cause?: Error): SubscriptionError {
|
|
27
|
+
return new SubscriptionError(message, 'RESTORE_FAILED', cause);
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
static networkError(message: string = 'Network error'): SubscriptionError {
|
|
33
|
-
return new SubscriptionError(message, 'NETWORK_ERROR');
|
|
30
|
+
static networkError(message: string = 'Network error', cause?: Error): SubscriptionError {
|
|
31
|
+
return new SubscriptionError(message, 'NETWORK_ERROR', cause);
|
|
34
32
|
}
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
export class SubscriptionRepositoryError extends
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
constructor(message: string, code: string = 'REPOSITORY_ERROR') {
|
|
41
|
-
super(message);
|
|
35
|
+
export class SubscriptionRepositoryError extends BaseError {
|
|
36
|
+
constructor(message: string, code: string = 'REPOSITORY_ERROR', cause?: Error) {
|
|
37
|
+
super(message, code, cause);
|
|
42
38
|
this.name = 'SubscriptionRepositoryError';
|
|
43
|
-
this.code = code;
|
|
44
|
-
Object.setPrototypeOf(this, SubscriptionRepositoryError.prototype);
|
|
45
39
|
}
|
|
46
40
|
}
|
|
47
41
|
|
|
48
|
-
export class SubscriptionValidationError extends
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
constructor(message: string, code: string = 'VALIDATION_ERROR') {
|
|
52
|
-
super(message);
|
|
42
|
+
export class SubscriptionValidationError extends BaseError {
|
|
43
|
+
constructor(message: string, code: string = 'VALIDATION_ERROR', cause?: Error) {
|
|
44
|
+
super(message, code, cause);
|
|
53
45
|
this.name = 'SubscriptionValidationError';
|
|
54
|
-
this.code = code;
|
|
55
|
-
Object.setPrototypeOf(this, SubscriptionValidationError.prototype);
|
|
56
46
|
}
|
|
57
47
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App and Platform Utilities
|
|
3
|
+
*/
|
|
4
|
+
import { Platform } from "react-native";
|
|
5
|
+
import Constants from "expo-constants";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Gets the current app version from Expo constants
|
|
9
|
+
*/
|
|
10
|
+
export function getAppVersion(): string {
|
|
11
|
+
const version = Constants.expoConfig?.version ?? Constants.manifest2?.extra?.expoClient?.version;
|
|
12
|
+
if (!version) {
|
|
13
|
+
throw new Error("appVersion is required in expoConfig");
|
|
14
|
+
}
|
|
15
|
+
return version;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validates if the current platform is supported
|
|
20
|
+
*/
|
|
21
|
+
export function validatePlatform(): "ios" | "android" {
|
|
22
|
+
const platform = Platform.OS;
|
|
23
|
+
if (platform !== "ios" && platform !== "android") {
|
|
24
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
25
|
+
}
|
|
26
|
+
return platform;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks if the app is currently in development mode
|
|
31
|
+
*/
|
|
32
|
+
export function isDev(): boolean {
|
|
33
|
+
return __DEV__;
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a date is in the past
|
|
7
|
+
*/
|
|
8
|
+
export function isPast(date: Date | string | number): boolean {
|
|
9
|
+
const d = new Date(date);
|
|
10
|
+
return d.getTime() < Date.now();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Converts various timestamp formats to a safe Date object
|
|
15
|
+
*/
|
|
16
|
+
export function toSafeDate(ts: any): Date | null {
|
|
17
|
+
if (!ts) return null;
|
|
18
|
+
if (typeof ts.toDate === "function") return ts.toDate();
|
|
19
|
+
if (ts instanceof Date) return ts;
|
|
20
|
+
if (typeof ts === "string" || typeof ts === "number") {
|
|
21
|
+
const d = new Date(ts);
|
|
22
|
+
return isNaN(d.getTime()) ? null : d;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Formats a date to ISO string safely
|
|
29
|
+
*/
|
|
30
|
+
export function formatISO(date: Date | null): string | null {
|
|
31
|
+
return date ? date.toISOString() : null;
|
|
32
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -54,9 +54,5 @@ export function detectPackageType(productIdentifier: string): SubscriptionPackag
|
|
|
54
54
|
return PACKAGE_TYPE.LIFETIME;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
if (__DEV__ && productIdentifier !== 'no_subscription') {
|
|
58
|
-
console.warn("[PackageTypeDetector] Unknown package type for:", productIdentifier);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
57
|
return PACKAGE_TYPE.UNKNOWN;
|
|
62
58
|
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wallet Screen Container
|
|
3
|
-
*
|
|
4
|
-
* Self-contained wallet screen.
|
|
5
|
-
* Uses global config from configureWallet() - no props needed!
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* 1. Call configureWallet() during app init
|
|
9
|
-
* 2. Use WalletScreenContainer directly in navigation
|
|
10
|
-
*
|
|
11
|
-
* ```tsx
|
|
12
|
-
* // In init
|
|
13
|
-
* configureWallet({ translations: myTranslations });
|
|
14
|
-
*
|
|
15
|
-
* // In navigation
|
|
16
|
-
* <Stack.Screen name="Wallet" component={WalletScreenContainer} />
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import React, { useMemo } from "react";
|
|
21
|
-
import { useNavigation } from "@react-navigation/native";
|
|
22
|
-
import { WalletScreen, type WalletScreenTranslations } from "./WalletScreen";
|
|
23
|
-
import { useWallet } from "../hooks/useWallet";
|
|
24
|
-
import { getWalletConfig } from "../../infrastructure/config/walletConfig";
|
|
25
|
-
|
|
26
|
-
export interface WalletScreenContainerProps {
|
|
27
|
-
/** Translations (overrides global config) */
|
|
28
|
-
translations?: WalletScreenTranslations;
|
|
29
|
-
/** Override onBack handler (default: navigation.goBack) */
|
|
30
|
-
onBack?: () => void;
|
|
31
|
-
/** Custom date formatter */
|
|
32
|
-
dateFormatter?: (timestamp: number) => string;
|
|
33
|
-
/** Footer component */
|
|
34
|
-
footer?: React.ReactNode;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const WalletScreenContainer: React.FC<WalletScreenContainerProps> = ({
|
|
38
|
-
translations,
|
|
39
|
-
onBack,
|
|
40
|
-
dateFormatter,
|
|
41
|
-
footer,
|
|
42
|
-
}) => {
|
|
43
|
-
const navigation = useNavigation();
|
|
44
|
-
const config = getWalletConfig();
|
|
45
|
-
|
|
46
|
-
const {
|
|
47
|
-
balance,
|
|
48
|
-
balanceLoading,
|
|
49
|
-
transactions,
|
|
50
|
-
transactionsLoading,
|
|
51
|
-
} = useWallet({
|
|
52
|
-
transactionConfig: {
|
|
53
|
-
collectionName: config.transactionCollection,
|
|
54
|
-
useUserSubcollection: config.useUserSubcollection,
|
|
55
|
-
},
|
|
56
|
-
transactionLimit: config.transactionLimit,
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const screenConfig = useMemo(
|
|
60
|
-
() => ({
|
|
61
|
-
balance,
|
|
62
|
-
balanceLoading,
|
|
63
|
-
transactions,
|
|
64
|
-
transactionsLoading,
|
|
65
|
-
translations: translations ?? config.translations,
|
|
66
|
-
onBack: onBack ?? (() => navigation.goBack()),
|
|
67
|
-
dateFormatter,
|
|
68
|
-
balanceIconName: config.balanceIconName,
|
|
69
|
-
footer,
|
|
70
|
-
}),
|
|
71
|
-
[
|
|
72
|
-
balance,
|
|
73
|
-
balanceLoading,
|
|
74
|
-
transactions,
|
|
75
|
-
transactionsLoading,
|
|
76
|
-
translations,
|
|
77
|
-
config,
|
|
78
|
-
onBack,
|
|
79
|
-
navigation,
|
|
80
|
-
dateFormatter,
|
|
81
|
-
footer,
|
|
82
|
-
],
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
return <WalletScreen config={screenConfig} />;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export default WalletScreenContainer;
|