@umituz/react-native-subscription 2.27.96 → 2.27.97

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 (33) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/core/Credits.ts +3 -11
  3. package/src/domains/paywall/components/PaywallContainer.tsx +17 -1
  4. package/src/domains/paywall/components/PaywallContainer.types.ts +2 -1
  5. package/src/domains/paywall/hooks/usePaywallActions.ts +1 -1
  6. package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +32 -12
  7. package/src/domains/subscription/infrastructure/hooks/subscriptionQueryKeys.ts +4 -4
  8. package/src/domains/subscription/infrastructure/hooks/useSubscriptionPackages.ts +1 -7
  9. package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -2
  10. package/src/domains/subscription/infrastructure/utils/InitializationCache.ts +20 -7
  11. package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +1 -1
  12. package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.tsx +55 -16
  13. package/src/domains/subscription/presentation/screens/components/CreditsList.tsx +14 -1
  14. package/src/domains/subscription/presentation/screens/components/DevTestSection.tsx +10 -2
  15. package/src/domains/subscription/presentation/screens/components/SubscriptionActions.tsx +6 -1
  16. package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.tsx +20 -1
  17. package/src/domains/subscription/presentation/screens/components/UpgradePrompt.tsx +13 -1
  18. package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +1 -1
  19. package/src/domains/subscription/presentation/useFeatureGate.ts +11 -7
  20. package/src/domains/subscription/presentation/usePaywallVisibility.ts +1 -1
  21. package/src/domains/subscription/presentation/useSubscriptionStatus.ts +1 -5
  22. package/src/init/index.ts +0 -3
  23. package/src/presentation/hooks/index.ts +0 -4
  24. package/src/shared/infrastructure/SubscriptionEventBus.ts +27 -0
  25. package/src/utils/packageTypeDetector.ts +0 -4
  26. package/src/domains/subscription/presentation/types/README.md +0 -22
  27. package/src/domains/subscription/presentation/types/SubscriptionDetailTypes.ts +0 -153
  28. package/src/domains/subscription/presentation/types/SubscriptionSettingsTypes.ts +0 -74
  29. package/src/domains/subscription/presentation/useAuthSubscriptionSync.ts +0 -63
  30. package/src/domains/subscription/presentation/usePremiumGate.ts +0 -84
  31. package/src/domains/subscription/presentation/useSavedPurchaseAutoExecution.ts +0 -148
  32. package/src/domains/subscription/presentation/useSubscriptionSettingsConfig.ts +0 -115
  33. package/src/domains/subscription/presentation/useSubscriptionSettingsConfig.utils.ts +0 -57
@@ -1,153 +0,0 @@
1
- /**
2
- * Subscription Detail Types
3
- * Type definitions for subscription detail screen and components
4
- */
5
-
6
- import type { SubscriptionStatusType } from "../../core/SubscriptionStatus";
7
- import type { CreditInfo } from "../components/details/PremiumDetailsCardTypes";
8
-
9
- export type { SubscriptionStatusType, CreditInfo };
10
-
11
- /** Translation strings for subscription detail screen */
12
- export interface SubscriptionDetailTranslations {
13
- title: string;
14
- statusLabel: string;
15
- statusActive: string;
16
- statusExpired: string;
17
- statusInactive: string;
18
- statusCanceled: string;
19
- /** Free status label */
20
- statusFree: string;
21
- /** Trial status label (defaults to statusActive if not provided) */
22
- statusTrial?: string;
23
- /** Trial canceled status label (defaults to statusCanceled if not provided) */
24
- statusTrialCanceled?: string;
25
- expiresLabel: string;
26
- purchasedLabel: string;
27
- lifetimeLabel: string;
28
- creditsTitle: string;
29
- remainingLabel: string;
30
- usageTitle?: string;
31
- manageButton: string;
32
- upgradeButton: string;
33
- creditsResetInfo?: string;
34
- }
35
-
36
- /** Dev test action callbacks */
37
- export interface DevTestActions {
38
- onTestRenewal: () => Promise<void>;
39
- onCheckCredits: () => void;
40
- onTestDuplicate: () => Promise<void>;
41
- }
42
-
43
- /** Dev tools configuration */
44
- export interface DevToolsConfig {
45
- actions: DevTestActions;
46
- title?: string;
47
- }
48
-
49
- /** Benefit item for upgrade prompt */
50
- export interface UpgradeBenefit {
51
- icon?: string;
52
- text: string;
53
- }
54
-
55
- /** Upgrade prompt configuration */
56
- export interface UpgradePromptConfig {
57
- title: string;
58
- subtitle?: string;
59
- benefits?: UpgradeBenefit[];
60
- }
61
-
62
- /** Display flags - centralized UI visibility control */
63
- export interface SubscriptionDisplayFlags {
64
- showHeader: boolean;
65
- showCredits: boolean;
66
- showUpgradePrompt: boolean;
67
- showExpirationDate: boolean;
68
- }
69
-
70
- /** Configuration for subscription detail screen */
71
- export interface SubscriptionDetailConfig {
72
- statusType: SubscriptionStatusType;
73
- isPremium: boolean;
74
- display: SubscriptionDisplayFlags;
75
- expirationDate?: string | null;
76
- purchaseDate?: string | null;
77
- isLifetime?: boolean;
78
- daysRemaining?: number | null;
79
- willRenew?: boolean;
80
- credits?: CreditInfo[];
81
- translations: SubscriptionDetailTranslations;
82
- onManageSubscription?: () => void;
83
- onUpgrade?: () => void;
84
- devTools?: DevToolsConfig;
85
- upgradePrompt?: UpgradePromptConfig;
86
- }
87
-
88
- /** Props for subscription detail screen */
89
- export interface SubscriptionDetailScreenProps {
90
- config: SubscriptionDetailConfig;
91
- }
92
-
93
- /** Props for subscription header component */
94
- export interface SubscriptionHeaderProps {
95
- statusType: SubscriptionStatusType;
96
- showExpirationDate: boolean;
97
- isLifetime?: boolean;
98
- expirationDate?: string | null;
99
- purchaseDate?: string | null;
100
- daysRemaining?: number | null;
101
- translations: Pick<
102
- SubscriptionDetailTranslations,
103
- | "title"
104
- | "statusLabel"
105
- | "statusActive"
106
- | "statusExpired"
107
- | "statusInactive"
108
- | "statusCanceled"
109
- | "statusTrial"
110
- | "statusTrialCanceled"
111
- | "expiresLabel"
112
- | "purchasedLabel"
113
- | "lifetimeLabel"
114
- > & { statusFree: string };
115
- }
116
-
117
- /** Props for credits list component */
118
- export interface CreditsListProps {
119
- credits: CreditInfo[];
120
- title?: string;
121
- description?: string;
122
- remainingLabel?: string;
123
- }
124
-
125
- /** Props for credit row component */
126
- export interface CreditRowProps {
127
- label: string;
128
- current: number;
129
- total: number;
130
- remainingLabel?: string;
131
- }
132
-
133
- /** Props for subscription actions component */
134
- export interface SubscriptionActionsProps {
135
- isPremium: boolean;
136
- upgradeButtonLabel?: string;
137
- onUpgrade?: () => void;
138
- }
139
-
140
- /** Props for dev test section */
141
- export interface DevTestSectionProps {
142
- actions: DevTestActions;
143
- title?: string;
144
- }
145
-
146
- /** Props for upgrade prompt component */
147
- export interface UpgradePromptProps {
148
- title: string;
149
- subtitle?: string;
150
- benefits?: UpgradeBenefit[];
151
- upgradeButtonLabel?: string;
152
- onUpgrade?: () => void;
153
- }
@@ -1,74 +0,0 @@
1
- /**
2
- * Subscription Settings Types
3
- * Type definitions for subscription settings configuration
4
- */
5
-
6
- import type { SubscriptionStatusType } from "../../core/SubscriptionConstants";
7
- import type {
8
- SubscriptionDetailConfig,
9
- UpgradePromptConfig,
10
- } from "./SubscriptionDetailTypes";
11
-
12
- export type { SubscriptionStatusType, UpgradePromptConfig };
13
-
14
- /** Configuration for settings list item */
15
- export interface SubscriptionSettingsItemConfig {
16
- title: string;
17
- description?: string;
18
- isPremium: boolean;
19
- statusLabel: string;
20
- icon?: string;
21
- onPress?: () => void;
22
- }
23
-
24
- /** Complete subscription settings configuration */
25
- export interface SubscriptionSettingsConfig {
26
- /** Whether subscription section should be shown */
27
- enabled: boolean;
28
- /** Config for settings list item */
29
- settingsItem: SubscriptionSettingsItemConfig;
30
- /** Config for detail screen */
31
- sectionConfig: SubscriptionDetailConfig;
32
- }
33
-
34
- /** Translation strings for subscription settings */
35
- export interface SubscriptionSettingsTranslations {
36
- /** Settings item title */
37
- title: string;
38
- /** Settings item description */
39
- description: string;
40
- /** Status labels */
41
- statusActive: string;
42
- statusInactive: string;
43
- statusExpired: string;
44
- statusCanceled: string;
45
- /** Trial status label (defaults to statusActive if not provided) */
46
- statusTrial?: string;
47
- /** Trial canceled status label (defaults to statusCanceled if not provided) */
48
- statusTrialCanceled?: string;
49
- /** Detail screen translations */
50
- statusLabel: string;
51
- expiresLabel: string;
52
- purchasedLabel: string;
53
- lifetimeLabel: string;
54
- creditsTitle: string;
55
- remainingLabel: string;
56
- manageButton: string;
57
- upgradeButton: string;
58
- /** Credit label (e.g., "Credits") */
59
- creditsLabel: string;
60
- }
61
-
62
- /** Parameters for useSubscriptionSettingsConfig hook */
63
- export interface UseSubscriptionSettingsConfigParams {
64
- /** User ID (required for credits lookup) */
65
- userId?: string;
66
- /** Whether user is anonymous */
67
- isAnonymous?: boolean;
68
- /** Translation strings */
69
- translations: SubscriptionSettingsTranslations;
70
- /** Fixed credit limit (if not available in UserCredits) */
71
- creditLimit?: number;
72
- /** Upgrade prompt configuration for free users */
73
- upgradePrompt?: UpgradePromptConfig;
74
- }
@@ -1,63 +0,0 @@
1
- /**
2
- * useAuthSubscriptionSync Hook
3
- * Single source of truth for RevenueCat initialization
4
- * Handles initial setup and auth state transitions
5
- * Generic implementation for 100+ apps with auth provider abstraction
6
- */
7
-
8
- import { useEffect, useRef, useCallback } from "react";
9
-
10
- export interface AuthSubscriptionSyncConfig {
11
- /** Function to subscribe to auth state changes - returns unsubscribe function */
12
- onAuthStateChanged: (callback: (userId: string | null) => void) => () => void;
13
- /** Function to initialize subscription for a user */
14
- initializeSubscription: (userId: string) => Promise<void>;
15
- }
16
-
17
- export function useAuthSubscriptionSync(
18
- config: AuthSubscriptionSyncConfig,
19
- ): void {
20
- const { onAuthStateChanged, initializeSubscription } = config;
21
- const previousUserIdRef = useRef<string | null>(null);
22
- const isInitializedRef = useRef(false);
23
-
24
- const initialize = useCallback(
25
- async (userId: string) => {
26
- await initializeSubscription(userId);
27
- },
28
- [initializeSubscription],
29
- );
30
-
31
- useEffect(() => {
32
- const unsubscribe = onAuthStateChanged(async (userId: string | null) => {
33
- if (!userId) {
34
- previousUserIdRef.current = null;
35
- return;
36
- }
37
-
38
- const previousUserId = previousUserIdRef.current;
39
-
40
- if (userId === previousUserId) {
41
- return;
42
- }
43
-
44
- try {
45
- if (previousUserId && previousUserId !== userId) {
46
- await initialize(userId);
47
- } else if (!isInitializedRef.current) {
48
- await initialize(userId);
49
- isInitializedRef.current = true;
50
- }
51
- } catch (error) {
52
- // Log error for debugging but don't crash the auth flow
53
- if (__DEV__) {
54
- console.error('[useAuthSubscriptionSync] Initialization failed:', error);
55
- }
56
- }
57
-
58
- previousUserIdRef.current = userId;
59
- });
60
-
61
- return () => unsubscribe();
62
- }, [onAuthStateChanged, initialize]);
63
- }
@@ -1,84 +0,0 @@
1
- /**
2
- * usePremiumGate Hook
3
- *
4
- * Simplified hook for premium-only apps (no credit system).
5
- * Provides screen-level and action-level premium gates.
6
- *
7
- * @example Screen-Level Gate
8
- * ```tsx
9
- * const { isPremium, requireScreen } = usePremiumGate();
10
- *
11
- * useEffect(() => {
12
- * requireScreen(); // Auto-opens paywall if not premium
13
- * }, [requireScreen]);
14
- *
15
- * if (!isPremium) return null;
16
- * ```
17
- *
18
- * @example Action-Level Gate
19
- * ```tsx
20
- * const { requirePremium } = usePremiumGate();
21
- *
22
- * const handleAction = () => {
23
- * requirePremium(() => {
24
- * // Action code here
25
- * });
26
- * };
27
- * ```
28
- */
29
-
30
- import { useCallback } from "react";
31
- import { useSubscriptionStatus } from "./useSubscriptionStatus";
32
- import { paywallControl } from "./usePaywallVisibility";
33
-
34
- export interface UsePremiumGateResult {
35
- /** Whether user has premium access */
36
- isPremium: boolean;
37
- /** Whether subscription status is loading */
38
- isLoading: boolean;
39
- /** Action-level gate: runs callback only if user has premium */
40
- requirePremium: (onSuccess: () => void) => void;
41
- /** Screen-level gate: opens paywall if not premium */
42
- requireScreen: () => void;
43
- }
44
-
45
- export const usePremiumGate = (): UsePremiumGateResult => {
46
- const { isPremium, isLoading } = useSubscriptionStatus();
47
-
48
- const requirePremium = useCallback(
49
- (onSuccess: () => void) => {
50
- if (isLoading) {
51
- return;
52
- }
53
-
54
- if (isPremium) {
55
- onSuccess();
56
- return;
57
- }
58
-
59
- paywallControl.open();
60
- },
61
- [isPremium, isLoading]
62
- );
63
-
64
- const requireScreen = useCallback(() => {
65
- if (!isLoading && !isPremium) {
66
- paywallControl.open();
67
- }
68
- }, [isPremium, isLoading]);
69
-
70
- return {
71
- isPremium,
72
- isLoading,
73
- requirePremium,
74
- requireScreen,
75
- };
76
- };
77
-
78
- /**
79
- * useSubscription Hook (Alias for usePremiumGate)
80
- *
81
- * Simpler name for premium-only apps.
82
- * Same functionality as usePremiumGate.
83
- */
84
- export const useSubscription = usePremiumGate;
@@ -1,148 +0,0 @@
1
- /**
2
- * Saved Purchase Auto-Execution Hook
3
- * Automatically executes saved purchase when user converts from anonymous to authenticated
4
- */
5
-
6
- import { useEffect, useRef } from "react";
7
- import {
8
- useAuthStore,
9
- selectUserId,
10
- selectIsAnonymous,
11
- } from "@umituz/react-native-auth";
12
- import { getSavedPurchase, clearSavedPurchase } from "./useAuthAwarePurchase";
13
- import { usePremium } from "./usePremium";
14
- import { SubscriptionManager } from "../infrastructure/managers/SubscriptionManager";
15
- import { usePurchaseLoadingStore } from "./stores";
16
-
17
- export interface UseSavedPurchaseAutoExecutionParams {
18
- onSuccess?: () => void;
19
- onError?: (error: Error) => void;
20
- }
21
-
22
- export interface UseSavedPurchaseAutoExecutionResult {
23
- isExecuting: boolean;
24
- }
25
-
26
- export const useSavedPurchaseAutoExecution = (
27
- params?: UseSavedPurchaseAutoExecutionParams
28
- ): UseSavedPurchaseAutoExecutionResult => {
29
- const { onSuccess, onError } = params ?? {};
30
-
31
- const userId = useAuthStore(selectUserId);
32
- const isAnonymous = useAuthStore(selectIsAnonymous);
33
-
34
- const { purchasePackage } = usePremium();
35
- const { startPurchase, endPurchase } = usePurchaseLoadingStore();
36
-
37
- const prevIsAnonymousRef = useRef<boolean | undefined>(undefined);
38
- const isExecutingRef = useRef(false);
39
- const hasExecutedRef = useRef(false);
40
-
41
- const purchasePackageRef = useRef(purchasePackage);
42
- const onSuccessRef = useRef(onSuccess);
43
- const onErrorRef = useRef(onError);
44
- const startPurchaseRef = useRef(startPurchase);
45
- const endPurchaseRef = useRef(endPurchase);
46
-
47
- // Consolidate all ref updates into a single effect
48
- useEffect(() => {
49
- purchasePackageRef.current = purchasePackage;
50
- onSuccessRef.current = onSuccess;
51
- onErrorRef.current = onError;
52
- startPurchaseRef.current = startPurchase;
53
- endPurchaseRef.current = endPurchase;
54
- }, [purchasePackage, onSuccess, onError, startPurchase, endPurchase]);
55
-
56
- useEffect(() => {
57
- const isAuthenticated = !!userId && !isAnonymous;
58
- const prevIsAnonymous = prevIsAnonymousRef.current;
59
- const savedPurchase = getSavedPurchase();
60
-
61
- const wasAnonymous = prevIsAnonymous === true;
62
- const becameAuthenticated = wasAnonymous && isAuthenticated;
63
-
64
- const shouldLog = prevIsAnonymousRef.current !== isAnonymous;
65
-
66
- if (typeof __DEV__ !== "undefined" && __DEV__ && shouldLog) {
67
- console.log("[SavedPurchaseAutoExecution] Auth state check:", {
68
- userId: userId?.slice(0, 8),
69
- prevIsAnonymous,
70
- isAnonymous,
71
- isAuthenticated,
72
- wasAnonymous,
73
- becameAuthenticated,
74
- hasSavedPurchase: !!savedPurchase,
75
- savedProductId: savedPurchase?.pkg.product.identifier,
76
- willExecute:
77
- becameAuthenticated &&
78
- !!savedPurchase &&
79
- !isExecutingRef.current &&
80
- !hasExecutedRef.current,
81
- });
82
- }
83
-
84
- if (
85
- becameAuthenticated &&
86
- savedPurchase &&
87
- !isExecutingRef.current &&
88
- !hasExecutedRef.current
89
- ) {
90
- hasExecutedRef.current = true;
91
- isExecutingRef.current = true;
92
-
93
- const executeFlow = async () => {
94
- const currentUserId = userId;
95
- if (!currentUserId) {
96
- isExecutingRef.current = false;
97
- return;
98
- }
99
-
100
- const maxAttempts = 20;
101
- const delayMs = 500;
102
-
103
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
104
- const isReady = SubscriptionManager.isInitializedForUser(currentUserId);
105
-
106
- if (isReady) {
107
- const pkg = savedPurchase.pkg;
108
-
109
- startPurchaseRef.current(pkg.product.identifier, "auto-execution");
110
-
111
- try {
112
- const success = await purchasePackageRef.current(pkg);
113
-
114
- if (success) {
115
- clearSavedPurchase();
116
- if (onSuccessRef.current) {
117
- onSuccessRef.current();
118
- }
119
- }
120
- } catch (error) {
121
- if (onErrorRef.current && error instanceof Error) {
122
- onErrorRef.current(error);
123
- }
124
- } finally {
125
- endPurchaseRef.current();
126
- isExecutingRef.current = false;
127
- }
128
-
129
- return;
130
- }
131
-
132
- await new Promise((resolve) => setTimeout(resolve, delayMs));
133
- }
134
-
135
- clearSavedPurchase();
136
- isExecutingRef.current = false;
137
- };
138
-
139
- executeFlow();
140
- }
141
-
142
- prevIsAnonymousRef.current = isAnonymous;
143
- }, [userId, isAnonymous]);
144
-
145
- return {
146
- isExecuting: isExecutingRef.current,
147
- };
148
- };
@@ -1,115 +0,0 @@
1
- /**
2
- * useSubscriptionSettingsConfig Hook
3
- * Returns ready-to-use config for settings screens
4
- */
5
-
6
- import { useMemo, useCallback } from "react";
7
- import { useCredits } from "../../credits/presentation/useCredits";
8
- import { usePaywallVisibility } from "./usePaywallVisibility";
9
- import { calculateDaysRemaining } from "../core/SubscriptionStatus";
10
- import { formatDate } from "./utils/subscriptionDateUtils";
11
- import { useCreditsArray, getSubscriptionStatusType } from "./useSubscriptionSettingsConfig.utils";
12
- import { getCreditsConfig } from "../../credits/infrastructure/CreditsRepositoryProvider";
13
- import type {
14
- SubscriptionSettingsConfig,
15
- SubscriptionStatusType,
16
- UseSubscriptionSettingsConfigParams,
17
- } from "./types/SubscriptionSettingsTypes";
18
-
19
- export type {
20
- SubscriptionSettingsConfig,
21
- SubscriptionSettingsItemConfig,
22
- SubscriptionSettingsTranslations,
23
- UseSubscriptionSettingsConfigParams,
24
- } from "./types/SubscriptionSettingsTypes";
25
-
26
- export const useSubscriptionSettingsConfig = (
27
- params: Omit<UseSubscriptionSettingsConfigParams, 'userId'>
28
- ): SubscriptionSettingsConfig => {
29
- const { translations, creditLimit, upgradePrompt } = params;
30
-
31
- const { credits } = useCredits();
32
- const { openPaywall } = usePaywallVisibility();
33
-
34
- const handleOpenPaywall = useCallback(() => {
35
- openPaywall("settings");
36
- }, [openPaywall]);
37
-
38
- const isPremium = credits?.isPremium ?? false;
39
- const willRenew = credits?.willRenew ?? false;
40
-
41
- const expiresAtIso = credits?.expirationDate?.toISOString() ?? null;
42
- const purchasedAtIso = credits?.purchasedAt?.toISOString() ?? null;
43
-
44
- const dynamicCreditLimit = useMemo(() => {
45
- if (credits?.creditLimit) return credits.creditLimit;
46
- const config = getCreditsConfig();
47
- return creditLimit ?? config.creditLimit;
48
- }, [credits?.creditLimit, creditLimit]);
49
-
50
- const formattedExpirationDate = useMemo(() => formatDate(expiresAtIso), [expiresAtIso]);
51
- const formattedPurchaseDate = useMemo(() => formatDate(purchasedAtIso), [purchasedAtIso]);
52
-
53
- const daysRemaining = useMemo(() => calculateDaysRemaining(expiresAtIso), [expiresAtIso]);
54
-
55
- const periodType = credits?.periodType;
56
-
57
- const statusType: SubscriptionStatusType = credits?.status
58
- ? (credits.status as SubscriptionStatusType)
59
- : getSubscriptionStatusType(isPremium, willRenew, expiresAtIso, periodType);
60
-
61
- const creditsArray = useCreditsArray(credits, dynamicCreditLimit, translations);
62
-
63
- const hasCredits = creditsArray.length > 0;
64
- const display = useMemo(() => ({
65
- showHeader: isPremium || hasCredits,
66
- showCredits: hasCredits,
67
- showUpgradePrompt: !isPremium && !hasCredits && !!upgradePrompt,
68
- showExpirationDate: (isPremium || hasCredits) && !!expiresAtIso,
69
- }), [isPremium, hasCredits, upgradePrompt, expiresAtIso]);
70
-
71
- return useMemo((): SubscriptionSettingsConfig => ({
72
- enabled: true,
73
- settingsItem: {
74
- title: translations.title,
75
- description: translations.description,
76
- isPremium,
77
- statusLabel: isPremium ? translations.statusActive : translations.statusInactive,
78
- icon: "diamond",
79
- onPress: handleOpenPaywall,
80
- },
81
- sectionConfig: {
82
- statusType,
83
- isPremium,
84
- display,
85
- expirationDate: formattedExpirationDate,
86
- purchaseDate: formattedPurchaseDate,
87
- isLifetime: isPremium && !expiresAtIso,
88
- daysRemaining,
89
- willRenew,
90
- credits: creditsArray,
91
- translations: {
92
- title: translations.title,
93
- statusLabel: translations.statusLabel,
94
- statusActive: translations.statusActive,
95
- statusExpired: translations.statusExpired,
96
- statusInactive: translations.statusInactive,
97
- statusCanceled: translations.statusCanceled,
98
- statusFree: translations.statusInactive,
99
- expiresLabel: translations.expiresLabel,
100
- purchasedLabel: translations.purchasedLabel,
101
- lifetimeLabel: translations.lifetimeLabel,
102
- creditsTitle: translations.creditsTitle,
103
- remainingLabel: translations.remainingLabel,
104
- manageButton: translations.manageButton,
105
- upgradeButton: translations.upgradeButton,
106
- },
107
- onUpgrade: handleOpenPaywall,
108
- upgradePrompt,
109
- },
110
- }), [
111
- translations, isPremium, statusType, display, formattedExpirationDate,
112
- formattedPurchaseDate, expiresAtIso, daysRemaining, willRenew,
113
- creditsArray, handleOpenPaywall, upgradePrompt,
114
- ]);
115
- };
@@ -1,57 +0,0 @@
1
- /**
2
- * useSubscriptionSettingsConfig Utilities
3
- * Helper functions for subscription settings config
4
- */
5
-
6
- import { useMemo } from "react";
7
- import type { UserCredits } from "../../credits/core/Credits";
8
- import { resolveSubscriptionStatus, type PeriodType, type SubscriptionStatusType } from "../core/SubscriptionStatus";
9
- import type { SubscriptionSettingsTranslations } from "./types/SubscriptionSettingsTypes";
10
-
11
- export interface CreditsInfo {
12
- id: string;
13
- label: string;
14
- current: number;
15
- total: number;
16
- }
17
-
18
- /**
19
- * Builds credits array for display
20
- */
21
- export function useCreditsArray(
22
- credits: UserCredits | null | undefined,
23
- creditLimit: number | undefined,
24
- translations: SubscriptionSettingsTranslations
25
- ): CreditsInfo[] {
26
- return useMemo(() => {
27
- if (!credits) return [];
28
- const validCredits = isNaN(credits.credits) ? 0 : credits.credits;
29
- return [
30
- {
31
- id: "credits",
32
- label: translations.creditsLabel,
33
- current: validCredits,
34
- total: creditLimit ?? validCredits,
35
- },
36
- ];
37
- }, [credits, creditLimit, translations.creditsLabel]);
38
- }
39
-
40
- /**
41
- * Calculates subscription status type based on premium, renewal status, and period type
42
- */
43
- export function getSubscriptionStatusType(
44
- isPremium: boolean,
45
- willRenew?: boolean,
46
- expiresAt?: string | null,
47
- periodType?: PeriodType | null
48
- ): SubscriptionStatusType {
49
- const isExpired = expiresAt ? new Date(expiresAt) < new Date() : false;
50
-
51
- return resolveSubscriptionStatus({
52
- isPremium,
53
- willRenew,
54
- isExpired,
55
- periodType: periodType ?? undefined,
56
- });
57
- }