@umituz/react-native-subscription 2.27.96 → 2.27.98

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 (44) hide show
  1. package/package.json +1 -1
  2. package/src/domains/credits/core/Credits.ts +3 -11
  3. package/src/domains/credits/presentation/useDeductCredit.ts +0 -4
  4. package/src/domains/paywall/components/PaywallContainer.tsx +17 -1
  5. package/src/domains/paywall/components/PaywallContainer.types.ts +2 -1
  6. package/src/domains/paywall/components/PaywallModal.tsx +0 -6
  7. package/src/domains/paywall/hooks/usePaywallActions.ts +1 -1
  8. package/src/domains/subscription/application/SubscriptionInitializer.ts +0 -6
  9. package/src/domains/subscription/infrastructure/handlers/PackageHandler.ts +23 -12
  10. package/src/domains/subscription/infrastructure/hooks/subscriptionQueryKeys.ts +4 -4
  11. package/src/domains/subscription/infrastructure/hooks/useCustomerInfo.ts +0 -19
  12. package/src/domains/subscription/infrastructure/hooks/useInitializeSubscription.ts +0 -16
  13. package/src/domains/subscription/infrastructure/hooks/usePurchasePackage.ts +0 -31
  14. package/src/domains/subscription/infrastructure/hooks/useRestorePurchase.ts +0 -27
  15. package/src/domains/subscription/infrastructure/hooks/useRevenueCatTrialEligibility.ts +0 -12
  16. package/src/domains/subscription/infrastructure/hooks/useSubscriptionPackages.ts +1 -7
  17. package/src/domains/subscription/infrastructure/hooks/useSubscriptionQueries.ts +0 -2
  18. package/src/domains/subscription/infrastructure/services/CustomerInfoListenerManager.ts +0 -21
  19. package/src/domains/subscription/infrastructure/services/RevenueCatInitializer.ts +0 -9
  20. package/src/domains/subscription/infrastructure/utils/InitializationCache.ts +20 -7
  21. package/src/domains/subscription/infrastructure/utils/PremiumStatusSyncer.ts +1 -16
  22. package/src/domains/subscription/presentation/screens/SubscriptionDetailScreen.tsx +49 -24
  23. package/src/domains/subscription/presentation/screens/components/CreditsList.tsx +14 -1
  24. package/src/domains/subscription/presentation/screens/components/SubscriptionActions.tsx +6 -1
  25. package/src/domains/subscription/presentation/screens/components/SubscriptionHeader.tsx +20 -1
  26. package/src/domains/subscription/presentation/screens/components/UpgradePrompt.tsx +13 -1
  27. package/src/domains/subscription/presentation/stores/purchaseLoadingStore.ts +0 -3
  28. package/src/domains/subscription/presentation/useAuthAwarePurchase.ts +1 -1
  29. package/src/domains/subscription/presentation/useFeatureGate.ts +9 -55
  30. package/src/domains/subscription/presentation/usePaywallVisibility.ts +1 -1
  31. package/src/domains/subscription/presentation/useSubscriptionStatus.ts +1 -5
  32. package/src/init/index.ts +0 -3
  33. package/src/presentation/hooks/index.ts +0 -4
  34. package/src/shared/infrastructure/SubscriptionEventBus.ts +27 -0
  35. package/src/utils/packageTypeDetector.ts +0 -4
  36. package/src/domains/subscription/presentation/screens/components/DevTestSection.tsx +0 -125
  37. package/src/domains/subscription/presentation/types/README.md +0 -22
  38. package/src/domains/subscription/presentation/types/SubscriptionDetailTypes.ts +0 -153
  39. package/src/domains/subscription/presentation/types/SubscriptionSettingsTypes.ts +0 -74
  40. package/src/domains/subscription/presentation/useAuthSubscriptionSync.ts +0 -63
  41. package/src/domains/subscription/presentation/usePremiumGate.ts +0 -84
  42. package/src/domains/subscription/presentation/useSavedPurchaseAutoExecution.ts +0 -148
  43. package/src/domains/subscription/presentation/useSubscriptionSettingsConfig.ts +0 -115
  44. package/src/domains/subscription/presentation/useSubscriptionSettingsConfig.utils.ts +0 -57
@@ -11,22 +11,55 @@ import {
11
11
  ScreenLayout,
12
12
  } from "@umituz/react-native-design-system";
13
13
  import { SubscriptionHeader } from "./components/SubscriptionHeader";
14
- import { CreditsList } from "./components/CreditsList";
15
- import { UpgradePrompt } from "./components/UpgradePrompt";
16
- import { DevTestSection } from "./components/DevTestSection";
17
- import type { SubscriptionDetailScreenProps } from "../types/SubscriptionDetailTypes";
14
+ import { CreditsList, type CreditItem } from "./components/CreditsList";
15
+ import { UpgradePrompt, type Benefit } from "./components/UpgradePrompt";
18
16
 
19
- export type {
20
- SubscriptionDisplayFlags,
21
- SubscriptionDetailTranslations,
22
- SubscriptionDetailConfig,
23
- SubscriptionDetailScreenProps,
24
- DevTestActions,
25
- DevToolsConfig,
26
- UpgradeBenefit,
27
- UpgradePromptConfig,
28
- UpgradePromptProps,
29
- } from "../types/SubscriptionDetailTypes";
17
+ export interface SubscriptionDisplayFlags {
18
+ showHeader: boolean;
19
+ showCredits: boolean;
20
+ showUpgradePrompt: boolean;
21
+ showExpirationDate: boolean;
22
+ }
23
+
24
+ export interface SubscriptionDetailTranslations {
25
+ title: string;
26
+ statusActive: string;
27
+ statusExpired: string;
28
+ statusFree: string;
29
+ statusCanceled: string;
30
+ statusLabel: string;
31
+ lifetimeLabel: string;
32
+ expiresLabel: string;
33
+ purchasedLabel: string;
34
+ usageTitle?: string;
35
+ creditsTitle: string;
36
+ creditsResetInfo?: string;
37
+ remainingLabel?: string;
38
+ upgradeButton: string;
39
+ }
40
+
41
+ export interface UpgradePromptConfig {
42
+ title: string;
43
+ subtitle?: string;
44
+ benefits?: readonly Benefit[];
45
+ onUpgrade?: () => void;
46
+ }
47
+
48
+ export interface SubscriptionDetailConfig {
49
+ display: SubscriptionDisplayFlags;
50
+ statusType: "active" | "expired" | "none" | "canceled";
51
+ isLifetime: boolean;
52
+ expirationDate?: string;
53
+ purchaseDate?: string;
54
+ daysRemaining?: number | null;
55
+ credits?: readonly CreditItem[];
56
+ translations: SubscriptionDetailTranslations;
57
+ upgradePrompt?: UpgradePromptConfig;
58
+ }
59
+
60
+ export interface SubscriptionDetailScreenProps {
61
+ config: SubscriptionDetailConfig;
62
+ }
30
63
 
31
64
  export const SubscriptionDetailScreen: React.FC<
32
65
  SubscriptionDetailScreenProps
@@ -59,14 +92,6 @@ export const SubscriptionDetailScreen: React.FC<
59
92
  edges={["bottom"]}
60
93
  backgroundColor={tokens.colors.backgroundPrimary}
61
94
  contentContainerStyle={styles.content}
62
- footer={
63
- config.devTools ? (
64
- <DevTestSection
65
- actions={config.devTools.actions}
66
- title={config.devTools.title}
67
- />
68
- ) : undefined
69
- }
70
95
  >
71
96
  <View style={styles.cardsContainer}>
72
97
  {showHeader && (
@@ -98,7 +123,7 @@ export const SubscriptionDetailScreen: React.FC<
98
123
  subtitle={config.upgradePrompt.subtitle}
99
124
  benefits={config.upgradePrompt.benefits}
100
125
  upgradeButtonLabel={config.translations.upgradeButton}
101
- onUpgrade={config.onUpgrade}
126
+ onUpgrade={config.upgradePrompt.onUpgrade ?? (() => {})}
102
127
  />
103
128
  )}
104
129
  </View>
@@ -7,7 +7,20 @@ import React, { useMemo } from "react";
7
7
  import { View, StyleSheet } from "react-native";
8
8
  import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
9
9
  import { CreditRow } from "../../components/details/CreditRow";
10
- import type { CreditsListProps } from "../../types/SubscriptionDetailTypes";
10
+
11
+ export interface CreditItem {
12
+ id: string;
13
+ label: string;
14
+ current: number;
15
+ total: number;
16
+ }
17
+
18
+ export interface CreditsListProps {
19
+ credits: readonly CreditItem[];
20
+ title?: string;
21
+ description?: string;
22
+ remainingLabel?: string;
23
+ }
11
24
 
12
25
  export const CreditsList: React.FC<CreditsListProps> = ({
13
26
  credits,
@@ -6,7 +6,12 @@
6
6
  import React, { useMemo } from "react";
7
7
  import { View, StyleSheet, TouchableOpacity } from "react-native";
8
8
  import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
9
- import type { SubscriptionActionsProps } from "../../types/SubscriptionDetailTypes";
9
+
10
+ export interface SubscriptionActionsProps {
11
+ isPremium: boolean;
12
+ upgradeButtonLabel?: string;
13
+ onUpgrade?: () => void;
14
+ }
10
15
 
11
16
  export const SubscriptionActions: React.FC<SubscriptionActionsProps> = ({
12
17
  isPremium,
@@ -8,7 +8,26 @@ import { View, StyleSheet } from "react-native";
8
8
  import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
9
9
  import { PremiumStatusBadge } from "../../components/details/PremiumStatusBadge";
10
10
  import { DetailRow } from "../../components/details/DetailRow";
11
- import type { SubscriptionHeaderProps } from "../../types/SubscriptionDetailTypes";
11
+
12
+ export interface SubscriptionHeaderProps {
13
+ statusType: "active" | "expired" | "none" | "canceled";
14
+ showExpirationDate: boolean;
15
+ isLifetime: boolean;
16
+ expirationDate?: string;
17
+ purchaseDate?: string;
18
+ daysRemaining?: number | null;
19
+ translations: {
20
+ title: string;
21
+ statusActive: string;
22
+ statusExpired: string;
23
+ statusFree: string;
24
+ statusCanceled: string;
25
+ statusLabel: string;
26
+ lifetimeLabel: string;
27
+ expiresLabel: string;
28
+ purchasedLabel: string;
29
+ };
30
+ }
12
31
 
13
32
  export const SubscriptionHeader: React.FC<SubscriptionHeaderProps> = ({
14
33
  statusType,
@@ -10,7 +10,19 @@ import {
10
10
  AtomicText,
11
11
  AtomicIcon,
12
12
  } from "@umituz/react-native-design-system";
13
- import type { UpgradePromptProps } from "../../types/SubscriptionDetailTypes";
13
+
14
+ export interface Benefit {
15
+ icon?: string;
16
+ text: string;
17
+ }
18
+
19
+ export interface UpgradePromptProps {
20
+ title: string;
21
+ subtitle?: string;
22
+ benefits?: readonly Benefit[];
23
+ upgradeButtonLabel: string;
24
+ onUpgrade: () => void;
25
+ }
14
26
 
15
27
  export const UpgradePrompt: React.FC<UpgradePromptProps> = ({
16
28
  title,
@@ -49,7 +49,6 @@ export const usePurchaseLoadingStore = create<PurchaseLoadingStore>((set, get) =
49
49
  // Still update to the new purchase to recover from potential stuck state
50
50
  }
51
51
  if (__DEV__) {
52
- console.log("[PurchaseLoadingStore] startPurchase:", { productId, source });
53
52
  }
54
53
  set({
55
54
  isPurchasing: true,
@@ -67,7 +66,6 @@ export const usePurchaseLoadingStore = create<PurchaseLoadingStore>((set, get) =
67
66
  // Reset to initial state to recover from potential stuck state
68
67
  }
69
68
  if (__DEV__) {
70
- console.log("[PurchaseLoadingStore] endPurchase");
71
69
  }
72
70
  set({
73
71
  isPurchasing: false,
@@ -78,7 +76,6 @@ export const usePurchaseLoadingStore = create<PurchaseLoadingStore>((set, get) =
78
76
 
79
77
  reset: () => {
80
78
  if (__DEV__) {
81
- console.log("[PurchaseLoadingStore] reset");
82
79
  }
83
80
  set(initialState);
84
81
  },
@@ -6,7 +6,7 @@
6
6
  import { useCallback } from "react";
7
7
  import type { PurchasesPackage } from "react-native-purchases";
8
8
  import { usePremium } from "./usePremium";
9
- import type { PurchaseSource } from "../../credits/core/Credits";
9
+ import type { PurchaseSource } from "../core/SubscriptionConstants";
10
10
 
11
11
  export interface PurchaseAuthProvider {
12
12
  isAuthenticated: () => boolean;
@@ -64,48 +64,19 @@ export function useFeatureGate(params: UseFeatureGateParams): UseFeatureGateResu
64
64
  }, [requiredCredits]);
65
65
 
66
66
  useEffect(() => {
67
- if (typeof __DEV__ !== "undefined" && __DEV__) {
68
- console.log("[useFeatureGate] Auth credits effect", {
69
- isWaiting: isWaitingForAuthCreditsRef.current,
70
- isLoaded: isCreditsLoaded,
71
- hasPending: !!pendingActionRef.current,
72
- credits: creditBalance,
73
- });
74
- }
75
-
76
67
  if (!isWaitingForAuthCreditsRef.current || !isCreditsLoaded || !pendingActionRef.current) {
77
68
  return;
78
69
  }
79
70
 
80
- if (typeof __DEV__ !== "undefined" && __DEV__) {
81
- console.log("[useFeatureGate] Credits loaded after auth", {
82
- credits: creditBalance,
83
- hasSubscription,
84
- isCreditsLoaded,
85
- });
86
- }
87
-
88
71
  isWaitingForAuthCreditsRef.current = false;
89
72
 
90
73
  if (hasSubscription || creditBalance >= requiredCredits) {
91
74
  const action = pendingActionRef.current;
92
75
  pendingActionRef.current = null;
93
-
94
- if (typeof __DEV__ !== "undefined" && __DEV__) {
95
- console.log("[useFeatureGate] Proceeding with action after auth", {
96
- credits: creditBalance,
97
- hasSubscription,
98
- });
99
- }
100
76
  action();
101
77
  return;
102
78
  }
103
79
 
104
- if (typeof __DEV__ !== "undefined" && __DEV__) {
105
- console.log("[useFeatureGate] No credits after auth, showing paywall", {
106
- credits: creditBalance,
107
- });
108
- }
109
80
  isWaitingForPurchaseRef.current = true;
110
81
  onShowPaywall(requiredCredits);
111
82
  }, [isCreditsLoaded, creditBalance, hasSubscription, requiredCredits, onShowPaywall]);
@@ -119,10 +90,6 @@ export function useFeatureGate(params: UseFeatureGateParams): UseFeatureGateResu
119
90
  const action = pendingActionRef.current;
120
91
  pendingActionRef.current = null;
121
92
  isWaitingForPurchaseRef.current = false;
122
-
123
- if (typeof __DEV__ !== "undefined" && __DEV__) {
124
- console.log("[useFeatureGate] Access acquired (credits or subscription), executing pending action");
125
- }
126
93
  action();
127
94
  }
128
95
 
@@ -132,48 +99,35 @@ export function useFeatureGate(params: UseFeatureGateParams): UseFeatureGateResu
132
99
 
133
100
  const requireFeature = useCallback(
134
101
  (action: () => void | Promise<void>) => {
135
- if (typeof __DEV__ !== "undefined" && __DEV__) {
136
- console.log("[useFeatureGate] requireFeature", {
137
- isAuthenticated,
138
- hasSubscription,
139
- creditBalance: creditBalanceRef.current,
140
- requiredCredits,
141
- isCreditsLoaded,
142
- });
143
- }
144
-
145
102
  if (!isAuthenticated) {
146
103
  const postAuthAction = () => {
147
104
  pendingActionRef.current = action;
148
105
  isWaitingForAuthCreditsRef.current = true;
149
-
150
- if (typeof __DEV__ !== "undefined" && __DEV__) {
151
- console.log("[useFeatureGate] Auth completed, waiting for credits to load");
152
- }
153
106
  };
154
107
  onShowAuthModal(postAuthAction);
155
108
  return;
156
109
  }
157
110
 
158
- if (hasSubscription) {
111
+ // Use ref values to avoid stale closure
112
+ const currentHasSubscription = hasSubscriptionRef.current;
113
+ const currentBalance = creditBalanceRef.current;
114
+ const currentRequiredCredits = requiredCreditsRef.current;
115
+
116
+ if (currentHasSubscription) {
159
117
  action();
160
118
  return;
161
119
  }
162
120
 
163
- const currentBalance = creditBalanceRef.current;
164
- if (currentBalance < requiredCredits) {
165
- if (typeof __DEV__ !== "undefined" && __DEV__) {
166
- console.log("[useFeatureGate] No credits, showing paywall");
167
- }
121
+ if (currentBalance < currentRequiredCredits) {
168
122
  pendingActionRef.current = action;
169
123
  isWaitingForPurchaseRef.current = true;
170
- onShowPaywall(requiredCredits);
124
+ onShowPaywallRef.current(currentRequiredCredits);
171
125
  return;
172
126
  }
173
127
 
174
128
  action();
175
129
  },
176
- [isAuthenticated, hasSubscription, requiredCredits, onShowAuthModal, onShowPaywall, isCreditsLoaded]
130
+ [isAuthenticated, onShowAuthModal, isCreditsLoaded]
177
131
  );
178
132
 
179
133
  const hasCredits = creditBalance >= requiredCredits;
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { useCallback, useSyncExternalStore } from "react";
8
- import type { PurchaseSource } from "../../credits/core/Credits";
8
+ import type { PurchaseSource } from "../core/SubscriptionConstants";
9
9
 
10
10
  type Listener = () => void;
11
11
 
@@ -48,11 +48,7 @@ export const useSubscriptionStatus = (): SubscriptionStatusResult => {
48
48
  }
49
49
  },
50
50
  enabled: !!userId && SubscriptionManager.isInitializedForUser(userId),
51
- staleTime: 30 * 1000, // 30 seconds
52
- gcTime: 5 * 60 * 1000, // 5 minutes
53
- refetchOnMount: "always",
54
- refetchOnWindowFocus: true,
55
- refetchOnReconnect: true,
51
+
56
52
  });
57
53
 
58
54
  return {
package/src/init/index.ts CHANGED
@@ -7,6 +7,3 @@ export {
7
7
  createSubscriptionInitModule,
8
8
  type SubscriptionInitModuleConfig,
9
9
  } from './createSubscriptionInitModule';
10
-
11
- // Re-export InitModule from design-system for convenience
12
- export type { InitModule } from '@umituz/react-native-design-system';
@@ -1,13 +1,9 @@
1
1
  export * from "../../domains/subscription/presentation/useAuthAwarePurchase";
2
- export * from "../../domains/subscription/presentation/useAuthSubscriptionSync";
3
- export * from "../../domains/subscription/presentation/useSavedPurchaseAutoExecution";
4
2
  export * from "../../domains/credits/presentation/useCredits";
5
3
  export * from "../../domains/credits/presentation/useDeductCredit";
6
4
  export * from "../../domains/subscription/presentation/useFeatureGate";
7
5
  export * from "../../domains/subscription/presentation/usePaywallVisibility";
8
6
  export * from "../../domains/subscription/presentation/usePremium";
9
- export * from "../../domains/subscription/presentation/usePremiumGate";
10
- export * from "../../domains/subscription/presentation/useSubscriptionSettingsConfig";
11
7
  export * from "../../domains/subscription/presentation/useSubscriptionStatus";
12
8
  export * from "./feedback/usePaywallFeedback";
13
9
  export * from "./feedback/useFeedbackSubmit";
@@ -28,6 +28,11 @@ export class SubscriptionEventBus {
28
28
  const listeners = this.listeners[event];
29
29
  if (listeners) {
30
30
  this.listeners[event] = listeners.filter(l => l !== callback);
31
+
32
+ // Clean up empty event arrays to prevent memory leak
33
+ if (this.listeners[event].length === 0) {
34
+ delete this.listeners[event];
35
+ }
31
36
  }
32
37
  };
33
38
  }
@@ -42,6 +47,28 @@ export class SubscriptionEventBus {
42
47
  }
43
48
  });
44
49
  }
50
+
51
+ /**
52
+ * Clear all listeners for a specific event or all events
53
+ * Useful for cleanup during testing or app state reset
54
+ */
55
+ clear(event?: string): void {
56
+ if (event) {
57
+ delete this.listeners[event];
58
+ } else {
59
+ this.listeners = {};
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Get listener count for debugging
65
+ */
66
+ getListenerCount(event?: string): number {
67
+ if (event) {
68
+ return this.listeners[event]?.length ?? 0;
69
+ }
70
+ return Object.values(this.listeners).reduce((total, arr) => total + arr.length, 0);
71
+ }
45
72
  }
46
73
 
47
74
  export const subscriptionEventBus = SubscriptionEventBus.getInstance();
@@ -7,10 +7,6 @@ import { PACKAGE_TYPE, type PackageType } from "../domains/subscription/core/Sub
7
7
 
8
8
  export type SubscriptionPackageType = PackageType;
9
9
 
10
- /**
11
- * Check if identifier is a credit package (consumable purchase)
12
- * Credit packages use a different system and don't need type detection
13
- */
14
10
  /**
15
11
  * Check if identifier is a credit package (consumable purchase)
16
12
  * Credit packages use a different system and don't need type detection
@@ -1,125 +0,0 @@
1
- /**
2
- * Dev Test Section
3
- * Developer testing tools for subscription renewals
4
- * Only visible in __DEV__ mode
5
- */
6
-
7
- import React, { useMemo } from "react";
8
- import { View, TouchableOpacity, StyleSheet } from "react-native";
9
- import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
10
- import type { DevTestSectionProps } from "../../types/SubscriptionDetailTypes";
11
-
12
- export type { DevTestActions, DevTestSectionProps } from "../../types/SubscriptionDetailTypes";
13
-
14
- /** Dev test button translations */
15
- export interface DevTestTranslations {
16
- title: string;
17
- testRenewal: string;
18
- checkCredits: string;
19
- testDuplicate: string;
20
- }
21
-
22
- export interface DevTestSectionWithTranslationsProps extends DevTestSectionProps {
23
- translations?: DevTestTranslations;
24
- }
25
-
26
- export const DevTestSection: React.FC<DevTestSectionWithTranslationsProps> = ({
27
- actions,
28
- title,
29
- translations,
30
- }) => {
31
- const tokens = useAppDesignTokens();
32
-
33
- const styles = useMemo(
34
- () =>
35
- StyleSheet.create({
36
- container: {
37
- padding: tokens.spacing.lg,
38
- gap: tokens.spacing.md,
39
- borderTopWidth: 1,
40
- backgroundColor: tokens.colors.surfaceSecondary,
41
- borderTopColor: tokens.colors.border,
42
- },
43
- title: {
44
- fontWeight: "600",
45
- marginBottom: tokens.spacing.xs,
46
- },
47
- button: {
48
- paddingVertical: tokens.spacing.md,
49
- paddingHorizontal: tokens.spacing.lg,
50
- borderRadius: tokens.radius.md,
51
- alignItems: "center",
52
- },
53
- primaryButton: {
54
- backgroundColor: tokens.colors.primary,
55
- },
56
- secondaryButton: {
57
- backgroundColor: tokens.colors.surfaceSecondary,
58
- borderWidth: 1,
59
- borderColor: tokens.colors.border,
60
- },
61
- buttonText: {
62
- fontWeight: "500",
63
- },
64
- }),
65
- [tokens]
66
- );
67
-
68
- if (!__DEV__) {
69
- return null;
70
- }
71
-
72
- const displayTitle = title || translations?.title;
73
- const renewalText = translations?.testRenewal || "Test Auto-Renewal";
74
- const creditsText = translations?.checkCredits || "Check Credits";
75
- const duplicateText = translations?.testDuplicate || "Test Duplicate Protection";
76
-
77
- return (
78
- <View style={styles.container}>
79
- {displayTitle && (
80
- <AtomicText
81
- type="titleMedium"
82
- style={[styles.title, { color: tokens.colors.textPrimary }]}
83
- >
84
- {displayTitle}
85
- </AtomicText>
86
- )}
87
-
88
- <TouchableOpacity
89
- style={[styles.button, styles.primaryButton]}
90
- onPress={actions.onTestRenewal}
91
- >
92
- <AtomicText
93
- type="bodyMedium"
94
- style={[styles.buttonText, { color: tokens.colors.onPrimary }]}
95
- >
96
- {renewalText}
97
- </AtomicText>
98
- </TouchableOpacity>
99
-
100
- <TouchableOpacity
101
- style={[styles.button, styles.secondaryButton]}
102
- onPress={actions.onCheckCredits}
103
- >
104
- <AtomicText
105
- type="bodyMedium"
106
- style={[styles.buttonText, { color: tokens.colors.textPrimary }]}
107
- >
108
- {creditsText}
109
- </AtomicText>
110
- </TouchableOpacity>
111
-
112
- <TouchableOpacity
113
- style={[styles.button, styles.secondaryButton]}
114
- onPress={actions.onTestDuplicate}
115
- >
116
- <AtomicText
117
- type="bodyMedium"
118
- style={[styles.buttonText, { color: tokens.colors.textPrimary }]}
119
- >
120
- {duplicateText}
121
- </AtomicText>
122
- </TouchableOpacity>
123
- </View>
124
- );
125
- };
@@ -1,22 +0,0 @@
1
- # Presentation Types
2
-
3
- TypeScript type definitions and interfaces for the presentation layer.
4
-
5
- ## Overview
6
-
7
- This directory contains all type definitions used by presentation components and hooks.
8
-
9
- ## Contents
10
-
11
- ### Subscription Types
12
-
13
- - **SubscriptionSettingsTypes.ts** - Configuration types for subscription settings UI
14
- - **PaywallTypes.ts** - Paywall component types
15
- - **SubscriptionTypes.ts** - General subscription UI types
16
-
17
- ## Key Exports
18
-
19
- ## Related
20
-
21
- - [Hooks](../hooks/README.md)
22
- - [Components](../components/README.md)