@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.
Files changed (61) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/application/CreditsInitializer.ts +28 -125
  3. package/src/domains/credits/application/credit-strategies/{CreditAllocationContext.ts → CreditAllocationOrchestrator.ts} +4 -9
  4. package/src/domains/credits/application/creditDocumentHelpers.ts +58 -0
  5. package/src/domains/credits/application/creditOperationUtils.ts +154 -0
  6. package/src/domains/credits/core/CreditsMapper.ts +8 -13
  7. package/src/domains/credits/infrastructure/{CreditsRepositoryProvider.ts → CreditsRepositoryManager.ts} +2 -2
  8. package/src/domains/credits/presentation/useCredits.ts +2 -3
  9. package/src/domains/credits/presentation/useDeductCredit.ts +4 -4
  10. package/src/domains/paywall/components/PaywallContainer.types.ts +1 -1
  11. package/src/domains/paywall/components/PaywallModal.tsx +28 -52
  12. package/src/domains/paywall/hooks/usePaywallActions.ts +77 -33
  13. package/src/domains/subscription/application/SubscriptionInitializer.ts +1 -1
  14. package/src/domains/subscription/application/SubscriptionSyncService.ts +17 -21
  15. package/src/domains/subscription/core/RevenueCatError.ts +40 -31
  16. package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +0 -1
  17. package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +19 -85
  18. package/src/domains/subscription/infrastructure/managers/SubscriptionManager.ts +33 -75
  19. package/src/domains/subscription/infrastructure/managers/subscriptionManagerUtils.ts +57 -0
  20. package/src/domains/subscription/infrastructure/services/CustomerInfoListenerManager.ts +3 -12
  21. package/src/domains/subscription/infrastructure/services/PurchaseHandler.ts +0 -2
  22. package/src/domains/subscription/infrastructure/services/RevenueCatInitializer.ts +2 -4
  23. package/src/domains/subscription/infrastructure/services/RevenueCatService.ts +1 -5
  24. package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +3 -12
  25. package/src/domains/subscription/infrastructure/utils/authPurchaseState.ts +69 -0
  26. package/src/domains/subscription/infrastructure/utils/trialEligibilityUtils.ts +77 -0
  27. package/src/domains/subscription/presentation/components/feedback/FeedbackOption.tsx +139 -0
  28. package/src/domains/subscription/presentation/components/feedback/PaywallFeedbackModal.tsx +15 -70
  29. package/src/domains/subscription/presentation/components/feedback/paywallFeedbackStyles.ts +0 -92
  30. package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.tsx +1 -1
  31. package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +1 -18
  32. package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +19 -69
  33. package/src/domains/subscription/presentation/usePaywallVisibility.ts +1 -1
  34. package/src/domains/subscription/presentation/usePremium.ts +2 -11
  35. package/src/domains/subscription/presentation/useSubscriptionStatus.ts +1 -6
  36. package/src/domains/trial/application/TrialService.ts +4 -8
  37. package/src/domains/wallet/index.ts +0 -6
  38. package/src/domains/wallet/infrastructure/repositories/TransactionRepository.ts +1 -1
  39. package/src/domains/wallet/infrastructure/services/ProductMetadataService.ts +0 -13
  40. package/src/domains/wallet/presentation/hooks/useProductMetadata.ts +0 -10
  41. package/src/domains/wallet/presentation/hooks/useTransactionHistory.ts +0 -8
  42. package/src/domains/wallet/presentation/screens/WalletScreen.tsx +57 -43
  43. package/src/index.ts +1 -1
  44. package/src/init/createSubscriptionInitModule.ts +1 -4
  45. package/src/presentation/hooks/feedback/useFeedbackSubmit.ts +0 -14
  46. package/src/shared/application/ActivationHandler.ts +6 -6
  47. package/src/shared/application/FeedbackService.ts +0 -21
  48. package/src/shared/infrastructure/SubscriptionEventBus.ts +1 -2
  49. package/src/shared/presentation/index.ts +1 -0
  50. package/src/shared/presentation/layouts/ScreenLayout.tsx +79 -0
  51. package/src/shared/types/CommonTypes.ts +65 -0
  52. package/src/shared/utils/BaseError.ts +26 -0
  53. package/src/shared/utils/Logger.ts +15 -46
  54. package/src/shared/utils/Result.ts +16 -0
  55. package/src/shared/utils/SubscriptionConfig.ts +1 -1
  56. package/src/shared/utils/SubscriptionError.ts +20 -30
  57. package/src/utils/appUtils.ts +34 -0
  58. package/src/utils/dateUtils.ts +32 -0
  59. package/src/utils/index.ts +2 -0
  60. package/src/utils/packageTypeDetector.ts +0 -4
  61. 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
- export class SubscriptionError extends Error {
7
- public readonly code: string;
6
+ import { BaseError } from "./BaseError";
8
7
 
9
- constructor(message: string, code: string = 'SUBSCRIPTION_ERROR') {
10
- super(message);
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 Error {
38
- public readonly code: string;
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 Error {
49
- public readonly code: string;
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
+ }
@@ -7,3 +7,5 @@ export * from "./priceUtils";
7
7
  export * from "./tierUtils";
8
8
  export * from "./types";
9
9
  export * from "./validation";
10
+ export * from "./dateUtils";
11
+ export * from "./appUtils";
@@ -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;