@umituz/react-native-subscription 2.14.10 → 2.14.11

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.
@@ -0,0 +1,88 @@
1
+ /**
2
+ * useProductMetadata Hook
3
+ *
4
+ * TanStack Query hook for fetching product metadata.
5
+ * Generic and reusable - uses config from ProductMetadataService.
6
+ */
7
+
8
+ import { useQuery } from "@tanstack/react-query";
9
+ import type {
10
+ ProductMetadata,
11
+ ProductMetadataConfig,
12
+ ProductType,
13
+ } from "../../domain/types/wallet.types";
14
+ import { ProductMetadataService } from "../../infrastructure/services/ProductMetadataService";
15
+
16
+ const CACHE_CONFIG = {
17
+ staleTime: 5 * 60 * 1000, // 5 minutes
18
+ gcTime: 30 * 60 * 1000, // 30 minutes
19
+ };
20
+
21
+ export const productMetadataQueryKeys = {
22
+ all: ["productMetadata"] as const,
23
+ byType: (type: ProductType) => ["productMetadata", type] as const,
24
+ };
25
+
26
+ export interface UseProductMetadataParams {
27
+ config: ProductMetadataConfig;
28
+ type?: ProductType;
29
+ enabled?: boolean;
30
+ }
31
+
32
+ export interface UseProductMetadataResult {
33
+ products: ProductMetadata[];
34
+ isLoading: boolean;
35
+ error: Error | null;
36
+ refetch: () => void;
37
+ creditsPackages: ProductMetadata[];
38
+ subscriptionPackages: ProductMetadata[];
39
+ }
40
+
41
+ export function useProductMetadata({
42
+ config,
43
+ type,
44
+ enabled = true,
45
+ }: UseProductMetadataParams): UseProductMetadataResult {
46
+ const service = new ProductMetadataService(config);
47
+
48
+ const queryKey = type
49
+ ? productMetadataQueryKeys.byType(type)
50
+ : productMetadataQueryKeys.all;
51
+
52
+ const { data, isLoading, error, refetch } = useQuery({
53
+ queryKey,
54
+ queryFn: async () => {
55
+ if (type) {
56
+ return service.getByType(type);
57
+ }
58
+ return service.getAll();
59
+ },
60
+ enabled,
61
+ staleTime: CACHE_CONFIG.staleTime,
62
+ gcTime: CACHE_CONFIG.gcTime,
63
+ });
64
+
65
+ const products = data ?? [];
66
+
67
+ const creditsPackages = products.filter((p) => p.type === "credits");
68
+ const subscriptionPackages = products.filter((p) => p.type === "subscription");
69
+
70
+ if (__DEV__) {
71
+ console.log("[useProductMetadata] State", {
72
+ enabled,
73
+ isLoading,
74
+ count: products.length,
75
+ credits: creditsPackages.length,
76
+ subscriptions: subscriptionPackages.length,
77
+ });
78
+ }
79
+
80
+ return {
81
+ products,
82
+ isLoading,
83
+ error: error as Error | null,
84
+ refetch,
85
+ creditsPackages,
86
+ subscriptionPackages,
87
+ };
88
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * useTransactionHistory Hook
3
+ *
4
+ * TanStack Query hook for fetching credit transaction history.
5
+ * Generic and reusable - uses config from TransactionRepository.
6
+ */
7
+
8
+ import { useQuery } from "@tanstack/react-query";
9
+ import type {
10
+ CreditLog,
11
+ TransactionRepositoryConfig,
12
+ } from "../../domain/types/transaction.types";
13
+ import { TransactionRepository } from "../../infrastructure/repositories/TransactionRepository";
14
+
15
+ const CACHE_CONFIG = {
16
+ staleTime: 60 * 1000, // 1 minute
17
+ gcTime: 5 * 60 * 1000, // 5 minutes
18
+ };
19
+
20
+ export const transactionQueryKeys = {
21
+ all: ["transactions"] as const,
22
+ user: (userId: string) => ["transactions", userId] as const,
23
+ };
24
+
25
+ export interface UseTransactionHistoryParams {
26
+ userId: string | undefined;
27
+ config: TransactionRepositoryConfig;
28
+ limit?: number;
29
+ enabled?: boolean;
30
+ }
31
+
32
+ export interface UseTransactionHistoryResult {
33
+ transactions: CreditLog[];
34
+ isLoading: boolean;
35
+ error: Error | null;
36
+ refetch: () => void;
37
+ isEmpty: boolean;
38
+ }
39
+
40
+ export function useTransactionHistory({
41
+ userId,
42
+ config,
43
+ limit = 50,
44
+ enabled = true,
45
+ }: UseTransactionHistoryParams): UseTransactionHistoryResult {
46
+ const repository = new TransactionRepository(config);
47
+
48
+ const { data, isLoading, error, refetch } = useQuery({
49
+ queryKey: [...transactionQueryKeys.user(userId ?? ""), limit],
50
+ queryFn: async () => {
51
+ if (!userId) return [];
52
+
53
+ const result = await repository.getTransactions({
54
+ userId,
55
+ limit,
56
+ });
57
+
58
+ if (!result.success) {
59
+ throw new Error(result.error?.message || "Failed to fetch history");
60
+ }
61
+
62
+ return result.data ?? [];
63
+ },
64
+ enabled: enabled && !!userId,
65
+ staleTime: CACHE_CONFIG.staleTime,
66
+ gcTime: CACHE_CONFIG.gcTime,
67
+ });
68
+
69
+ const transactions = data ?? [];
70
+
71
+ if (__DEV__) {
72
+ console.log("[useTransactionHistory] State", {
73
+ userId,
74
+ enabled,
75
+ isLoading,
76
+ count: transactions.length,
77
+ });
78
+ }
79
+
80
+ return {
81
+ transactions,
82
+ isLoading,
83
+ error: error as Error | null,
84
+ refetch,
85
+ isEmpty: transactions.length === 0,
86
+ };
87
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * useWallet Hook
3
+ *
4
+ * Orchestration hook for wallet functionality.
5
+ * Combines balance, transactions, and purchase state.
6
+ */
7
+
8
+ import { useCallback, useMemo } from "react";
9
+ import {
10
+ useCredits,
11
+ type UseCreditsParams,
12
+ } from "../../../../presentation/hooks/useCredits";
13
+ import {
14
+ useTransactionHistory,
15
+ type UseTransactionHistoryParams,
16
+ } from "./useTransactionHistory";
17
+ import type { CreditLog } from "../../domain/types/transaction.types";
18
+
19
+ export interface UseWalletParams {
20
+ userId: string | undefined;
21
+ transactionConfig: UseTransactionHistoryParams["config"];
22
+ transactionLimit?: number;
23
+ enabled?: boolean;
24
+ }
25
+
26
+ export interface UseWalletResult {
27
+ balance: number;
28
+ textCredits: number;
29
+ imageCredits: number;
30
+ balanceLoading: boolean;
31
+ transactions: CreditLog[];
32
+ transactionsLoading: boolean;
33
+ hasCredits: boolean;
34
+ refetchBalance: () => void;
35
+ refetchTransactions: () => void;
36
+ refetchAll: () => void;
37
+ }
38
+
39
+ export function useWallet({
40
+ userId,
41
+ transactionConfig,
42
+ transactionLimit = 50,
43
+ enabled = true,
44
+ }: UseWalletParams): UseWalletResult {
45
+ const creditsParams: UseCreditsParams = {
46
+ userId,
47
+ enabled,
48
+ };
49
+
50
+ const transactionParams: UseTransactionHistoryParams = {
51
+ userId,
52
+ config: transactionConfig,
53
+ limit: transactionLimit,
54
+ enabled,
55
+ };
56
+
57
+ const {
58
+ credits,
59
+ isLoading: balanceLoading,
60
+ refetch: refetchBalance,
61
+ hasTextCredits,
62
+ hasImageCredits,
63
+ } = useCredits(creditsParams);
64
+
65
+ const {
66
+ transactions,
67
+ isLoading: transactionsLoading,
68
+ refetch: refetchTransactions,
69
+ } = useTransactionHistory(transactionParams);
70
+
71
+ const balance = useMemo(() => {
72
+ if (!credits) return 0;
73
+ return credits.textCredits + credits.imageCredits;
74
+ }, [credits]);
75
+
76
+ const refetchAll = useCallback(() => {
77
+ refetchBalance();
78
+ refetchTransactions();
79
+ }, [refetchBalance, refetchTransactions]);
80
+
81
+ return {
82
+ balance,
83
+ textCredits: credits?.textCredits ?? 0,
84
+ imageCredits: credits?.imageCredits ?? 0,
85
+ balanceLoading,
86
+ transactions,
87
+ transactionsLoading,
88
+ hasCredits: hasTextCredits || hasImageCredits,
89
+ refetchBalance,
90
+ refetchTransactions,
91
+ refetchAll,
92
+ };
93
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Wallet Screen
3
+ *
4
+ * Generic wallet screen composition.
5
+ * Props-driven for full customization across apps.
6
+ * No business logic - pure presentation.
7
+ */
8
+
9
+ import React from "react";
10
+ import { View, StyleSheet, ActivityIndicator, TouchableOpacity } from "react-native";
11
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
12
+ import {
13
+ useAppDesignTokens,
14
+ AtomicText,
15
+ AtomicIcon,
16
+ ScreenLayout,
17
+ } from "@umituz/react-native-design-system";
18
+ import {
19
+ BalanceCard,
20
+ type BalanceCardTranslations,
21
+ } from "../components/BalanceCard";
22
+ import {
23
+ TransactionList,
24
+ type TransactionListTranslations,
25
+ } from "../components/TransactionList";
26
+ import type { CreditLog } from "../../domain/types/transaction.types";
27
+
28
+ export interface WalletScreenTranslations
29
+ extends BalanceCardTranslations,
30
+ TransactionListTranslations {
31
+ screenTitle: string;
32
+ }
33
+
34
+ export interface WalletScreenConfig {
35
+ balance: number;
36
+ balanceLoading: boolean;
37
+ transactions: CreditLog[];
38
+ transactionsLoading: boolean;
39
+ translations: WalletScreenTranslations;
40
+ onBack?: () => void;
41
+ dateFormatter?: (timestamp: number) => string;
42
+ maxTransactionHeight?: number;
43
+ balanceIconName?: string;
44
+ footer?: React.ReactNode;
45
+ }
46
+
47
+ export interface WalletScreenProps {
48
+ config: WalletScreenConfig;
49
+ }
50
+
51
+ export const WalletScreen: React.FC<WalletScreenProps> = ({ config }) => {
52
+ const tokens = useAppDesignTokens();
53
+ const insets = useSafeAreaInsets();
54
+
55
+ const renderHeader = () => (
56
+ <View style={[styles.header, { paddingTop: insets.top + 12 }]}>
57
+ {config.onBack && (
58
+ <TouchableOpacity
59
+ onPress={config.onBack}
60
+ style={styles.backButton}
61
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
62
+ >
63
+ <AtomicIcon
64
+ name="ArrowLeft"
65
+ size="lg"
66
+ customColor={tokens.colors.textPrimary}
67
+ />
68
+ </TouchableOpacity>
69
+ )}
70
+ <AtomicText
71
+ type="titleLarge"
72
+ style={{ color: tokens.colors.textPrimary, fontWeight: "700" }}
73
+ >
74
+ {config.translations.screenTitle}
75
+ </AtomicText>
76
+ </View>
77
+ );
78
+
79
+ const renderBalance = () => {
80
+ if (config.balanceLoading) {
81
+ return (
82
+ <View style={styles.loadingContainer}>
83
+ <ActivityIndicator size="large" color={tokens.colors.primary} />
84
+ <AtomicText
85
+ type="bodyMedium"
86
+ style={[styles.loadingText, { color: tokens.colors.textSecondary }]}
87
+ >
88
+ {config.translations.loading}
89
+ </AtomicText>
90
+ </View>
91
+ );
92
+ }
93
+
94
+ return (
95
+ <BalanceCard
96
+ balance={config.balance}
97
+ translations={config.translations}
98
+ iconName={config.balanceIconName}
99
+ />
100
+ );
101
+ };
102
+
103
+ return (
104
+ <ScreenLayout
105
+ scrollable={true}
106
+ edges={["bottom"]}
107
+ backgroundColor={tokens.colors.backgroundPrimary}
108
+ contentContainerStyle={styles.content}
109
+ footer={config.footer}
110
+ >
111
+ {renderHeader()}
112
+ {renderBalance()}
113
+ <TransactionList
114
+ transactions={config.transactions}
115
+ loading={config.transactionsLoading}
116
+ translations={config.translations}
117
+ maxHeight={config.maxTransactionHeight}
118
+ dateFormatter={config.dateFormatter}
119
+ />
120
+ </ScreenLayout>
121
+ );
122
+ };
123
+
124
+ const styles = StyleSheet.create({
125
+ content: {
126
+ paddingBottom: 24,
127
+ },
128
+ header: {
129
+ flexDirection: "row",
130
+ alignItems: "center",
131
+ paddingHorizontal: 16,
132
+ paddingBottom: 12,
133
+ },
134
+ backButton: {
135
+ marginRight: 16,
136
+ },
137
+ loadingContainer: {
138
+ padding: 40,
139
+ alignItems: "center",
140
+ justifyContent: "center",
141
+ gap: 12,
142
+ },
143
+ loadingText: {
144
+ fontSize: 14,
145
+ fontWeight: "500",
146
+ },
147
+ });
package/src/index.ts CHANGED
@@ -6,9 +6,11 @@
6
6
  */
7
7
 
8
8
  // =============================================================================
9
- // DOMAIN LAYER - Errors
9
+ // WALLET DOMAIN (Complete)
10
10
  // =============================================================================
11
11
 
12
+ export * from "./domains/wallet";
13
+
12
14
  // =============================================================================
13
15
  // DOMAIN LAYER - Subscription Status
14
16
  // =============================================================================
@@ -231,6 +233,9 @@ export type {
231
233
 
232
234
  export { DEFAULT_CREDITS_CONFIG } from "./domain/entities/Credits";
233
235
 
236
+ // CreditCost, Transaction types, Wallet types, Credit-cost types
237
+ // are now exported from "./domains/wallet"
238
+
234
239
  // =============================================================================
235
240
  // CREDITS SYSTEM - Repository
236
241
  // =============================================================================
@@ -240,6 +245,9 @@ export {
240
245
  createCreditsRepository,
241
246
  } from "./infrastructure/repositories/CreditsRepository";
242
247
 
248
+ // TransactionRepository and ProductMetadataService
249
+ // are now exported from "./domains/wallet"
250
+
243
251
  // =============================================================================
244
252
  // CREDITS SYSTEM - Configuration (Module-Level Provider)
245
253
  // =============================================================================
@@ -316,6 +324,9 @@ export {
316
324
 
317
325
  export { useDevTestCallbacks } from "./presentation/hooks/useDevTestCallbacks";
318
326
 
327
+ // Wallet hooks, components, and screens
328
+ // are now exported from "./domains/wallet"
329
+
319
330
  // =============================================================================
320
331
  // CREDITS SYSTEM - Utilities
321
332
  // =============================================================================