@umituz/react-native-subscription 2.10.2 → 2.10.3
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/index.ts +6 -12
- package/src/infrastructure/repositories/CreditsRepositoryProvider.ts +53 -0
- package/src/presentation/components/feedback/paywallFeedbackStyles.ts +2 -5
- package/src/presentation/components/paywall/PaywallModal.tsx +17 -15
- package/src/presentation/components/paywall/SubscriptionModal.tsx +12 -12
- package/src/presentation/components/paywall/SubscriptionTabContent.tsx +13 -18
- package/src/presentation/hooks/useCreditChecker.ts +4 -4
- package/src/presentation/hooks/useCredits.ts +6 -6
- package/src/presentation/hooks/useDeductCredit.ts +4 -4
- package/src/presentation/context/CreditsContext.ts +0 -42
- package/src/presentation/providers/CreditsProvider.tsx +0 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-subscription",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.3",
|
|
4
4
|
"description": "Complete subscription management with RevenueCat, paywall UI, and credits system for React Native apps",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -190,21 +190,15 @@ export {
|
|
|
190
190
|
} from "./infrastructure/repositories/CreditsRepository";
|
|
191
191
|
|
|
192
192
|
// =============================================================================
|
|
193
|
-
// CREDITS SYSTEM -
|
|
193
|
+
// CREDITS SYSTEM - Configuration (Module-Level Provider)
|
|
194
194
|
// =============================================================================
|
|
195
195
|
|
|
196
196
|
export {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
} from "./presentation/context/CreditsContext";
|
|
203
|
-
|
|
204
|
-
export {
|
|
205
|
-
CreditsProvider,
|
|
206
|
-
type CreditsProviderProps,
|
|
207
|
-
} from "./presentation/providers/CreditsProvider";
|
|
197
|
+
configureCreditsRepository,
|
|
198
|
+
getCreditsRepository,
|
|
199
|
+
getCreditsConfig,
|
|
200
|
+
resetCreditsRepository,
|
|
201
|
+
} from "./infrastructure/repositories/CreditsRepositoryProvider";
|
|
208
202
|
|
|
209
203
|
// =============================================================================
|
|
210
204
|
// CREDITS SYSTEM - Hooks
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credits Repository Provider
|
|
3
|
+
* Module-level singleton for credits repository configuration
|
|
4
|
+
* Replaces Context API with a simpler, testable approach
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { CreditsConfig } from "../../domain/entities/Credits";
|
|
8
|
+
import { DEFAULT_CREDITS_CONFIG } from "../../domain/entities/Credits";
|
|
9
|
+
import type { CreditsRepository } from "./CreditsRepository";
|
|
10
|
+
import { createCreditsRepository } from "./CreditsRepository";
|
|
11
|
+
|
|
12
|
+
let globalRepository: CreditsRepository | null = null;
|
|
13
|
+
let globalConfig: CreditsConfig = DEFAULT_CREDITS_CONFIG;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configure credits repository for the application
|
|
17
|
+
* Must be called once during app initialization
|
|
18
|
+
*/
|
|
19
|
+
export function configureCreditsRepository(config: Partial<CreditsConfig>): void {
|
|
20
|
+
globalConfig = {
|
|
21
|
+
...DEFAULT_CREDITS_CONFIG,
|
|
22
|
+
...config,
|
|
23
|
+
};
|
|
24
|
+
globalRepository = createCreditsRepository(globalConfig);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the configured credits repository
|
|
29
|
+
* Throws if repository not configured
|
|
30
|
+
*/
|
|
31
|
+
export function getCreditsRepository(): CreditsRepository {
|
|
32
|
+
if (!globalRepository) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"CreditsRepository not configured. Call configureCreditsRepository() first."
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return globalRepository;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the current credits configuration
|
|
42
|
+
*/
|
|
43
|
+
export function getCreditsConfig(): CreditsConfig {
|
|
44
|
+
return globalConfig;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Reset repository (for testing)
|
|
49
|
+
*/
|
|
50
|
+
export function resetCreditsRepository(): void {
|
|
51
|
+
globalRepository = null;
|
|
52
|
+
globalConfig = DEFAULT_CREDITS_CONFIG;
|
|
53
|
+
}
|
|
@@ -28,11 +28,8 @@ export const createPaywallFeedbackStyles = (
|
|
|
28
28
|
backgroundColor: tokens.colors.surface,
|
|
29
29
|
borderRadius: 24,
|
|
30
30
|
padding: 24,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
shadowOpacity: 0.25,
|
|
34
|
-
shadowRadius: 16,
|
|
35
|
-
elevation: 8,
|
|
31
|
+
borderWidth: 1,
|
|
32
|
+
borderColor: tokens.colors.border,
|
|
36
33
|
},
|
|
37
34
|
header: {
|
|
38
35
|
alignItems: "center",
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import React, { useEffect } from "react";
|
|
7
7
|
import { View, StyleSheet } from "react-native";
|
|
8
|
-
import {
|
|
9
|
-
import { useLocalization } from "@umituz/react-native-localization";
|
|
8
|
+
import { BaseModal, useResponsive } from "@umituz/react-native-design-system";
|
|
10
9
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
11
10
|
import { usePaywall } from "../../hooks/usePaywall";
|
|
12
11
|
import { PaywallHeader } from "./PaywallHeader";
|
|
@@ -35,8 +34,12 @@ export interface PaywallModalProps {
|
|
|
35
34
|
onRestore?: () => Promise<void>;
|
|
36
35
|
subscriptionFeatures?: Array<{ icon: string; text: string }>;
|
|
37
36
|
isLoading?: boolean;
|
|
38
|
-
title
|
|
39
|
-
subtitle
|
|
37
|
+
title: string;
|
|
38
|
+
subtitle: string;
|
|
39
|
+
creditsTabLabel: string;
|
|
40
|
+
subscriptionTabLabel: string;
|
|
41
|
+
purchaseButtonText: string;
|
|
42
|
+
subscribeButtonText: string;
|
|
40
43
|
privacyUrl?: string;
|
|
41
44
|
termsUrl?: string;
|
|
42
45
|
privacyText?: string;
|
|
@@ -60,6 +63,10 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
60
63
|
isLoading = false,
|
|
61
64
|
title,
|
|
62
65
|
subtitle,
|
|
66
|
+
creditsTabLabel,
|
|
67
|
+
subscriptionTabLabel,
|
|
68
|
+
purchaseButtonText,
|
|
69
|
+
subscribeButtonText,
|
|
63
70
|
privacyUrl,
|
|
64
71
|
termsUrl,
|
|
65
72
|
privacyText,
|
|
@@ -67,8 +74,6 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
67
74
|
restoreButtonText,
|
|
68
75
|
} = props;
|
|
69
76
|
|
|
70
|
-
const tokens = useAppDesignTokens();
|
|
71
|
-
const { t } = useLocalization();
|
|
72
77
|
const { modalLayout } = useResponsive();
|
|
73
78
|
|
|
74
79
|
const {
|
|
@@ -86,9 +91,6 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
86
91
|
onSubscriptionPurchase,
|
|
87
92
|
});
|
|
88
93
|
|
|
89
|
-
const displayTitle = title || t("paywall.title");
|
|
90
|
-
const displaySubtitle = subtitle || t("paywall.subtitle");
|
|
91
|
-
|
|
92
94
|
useEffect(() => {
|
|
93
95
|
if (__DEV__) {
|
|
94
96
|
console.log("[PaywallModal] State:", {
|
|
@@ -105,8 +107,8 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
105
107
|
<BaseModal visible={visible} onClose={onClose}>
|
|
106
108
|
<View style={styles.container}>
|
|
107
109
|
<PaywallHeader
|
|
108
|
-
title={
|
|
109
|
-
subtitle={
|
|
110
|
+
title={title}
|
|
111
|
+
subtitle={subtitle}
|
|
110
112
|
onClose={onClose}
|
|
111
113
|
variant="fullscreen"
|
|
112
114
|
/>
|
|
@@ -114,8 +116,8 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
114
116
|
<PaywallTabBar
|
|
115
117
|
activeTab={activeTab}
|
|
116
118
|
onTabChange={handleTabChange}
|
|
117
|
-
creditsLabel={
|
|
118
|
-
subscriptionLabel={
|
|
119
|
+
creditsLabel={creditsTabLabel}
|
|
120
|
+
subscriptionLabel={subscriptionTabLabel}
|
|
119
121
|
/>
|
|
120
122
|
|
|
121
123
|
<View style={styles.tabContent}>
|
|
@@ -128,7 +130,7 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
128
130
|
currentCredits={currentCredits}
|
|
129
131
|
requiredCredits={requiredCredits}
|
|
130
132
|
isLoading={isLoading}
|
|
131
|
-
purchaseButtonText={
|
|
133
|
+
purchaseButtonText={purchaseButtonText}
|
|
132
134
|
/>
|
|
133
135
|
) : (
|
|
134
136
|
<SubscriptionTabContent
|
|
@@ -138,7 +140,7 @@ export const PaywallModal: React.FC<PaywallModalProps> = React.memo((props) => {
|
|
|
138
140
|
onPurchase={handleSubscriptionPurchase}
|
|
139
141
|
features={subscriptionFeatures}
|
|
140
142
|
isLoading={isLoading}
|
|
141
|
-
purchaseButtonText={
|
|
143
|
+
purchaseButtonText={subscribeButtonText}
|
|
142
144
|
onRestore={onRestore}
|
|
143
145
|
privacyUrl={privacyUrl}
|
|
144
146
|
termsUrl={termsUrl}
|
|
@@ -20,15 +20,15 @@ export interface SubscriptionModalProps {
|
|
|
20
20
|
packages: PurchasesPackage[];
|
|
21
21
|
onPurchase: (pkg: PurchasesPackage) => Promise<boolean>;
|
|
22
22
|
onRestore: () => Promise<boolean>;
|
|
23
|
-
title
|
|
23
|
+
title: string;
|
|
24
24
|
subtitle?: string;
|
|
25
25
|
features?: Array<{ icon: string; text: string }>;
|
|
26
26
|
isLoading?: boolean;
|
|
27
|
-
purchaseButtonText
|
|
28
|
-
restoreButtonText
|
|
29
|
-
loadingText
|
|
30
|
-
emptyText
|
|
31
|
-
processingText
|
|
27
|
+
purchaseButtonText: string;
|
|
28
|
+
restoreButtonText: string;
|
|
29
|
+
loadingText: string;
|
|
30
|
+
emptyText: string;
|
|
31
|
+
processingText: string;
|
|
32
32
|
privacyUrl?: string;
|
|
33
33
|
termsUrl?: string;
|
|
34
34
|
privacyText?: string;
|
|
@@ -43,15 +43,15 @@ export const SubscriptionModal: React.FC<SubscriptionModalProps> = React.memo((p
|
|
|
43
43
|
packages,
|
|
44
44
|
onPurchase,
|
|
45
45
|
onRestore,
|
|
46
|
-
title
|
|
46
|
+
title,
|
|
47
47
|
subtitle,
|
|
48
48
|
features = [],
|
|
49
49
|
isLoading = false,
|
|
50
|
-
purchaseButtonText
|
|
51
|
-
restoreButtonText
|
|
52
|
-
loadingText
|
|
53
|
-
emptyText
|
|
54
|
-
processingText
|
|
50
|
+
purchaseButtonText,
|
|
51
|
+
restoreButtonText,
|
|
52
|
+
loadingText,
|
|
53
|
+
emptyText,
|
|
54
|
+
processingText,
|
|
55
55
|
privacyUrl,
|
|
56
56
|
termsUrl,
|
|
57
57
|
privacyText,
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import React, { useMemo } from "react";
|
|
7
7
|
import { View, StyleSheet, ScrollView } from "react-native";
|
|
8
8
|
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
9
|
-
import { useLocalization } from "@umituz/react-native-localization";
|
|
10
9
|
import type { PurchasesPackage } from "react-native-purchases";
|
|
11
10
|
import { PaywallFeaturesList } from "./PaywallFeaturesList";
|
|
12
11
|
import { SubscriptionPackageList } from "./SubscriptionPackageList";
|
|
@@ -20,9 +19,11 @@ interface SubscriptionTabContentProps {
|
|
|
20
19
|
onRestore?: () => void;
|
|
21
20
|
features?: Array<{ icon: string; text: string }>;
|
|
22
21
|
isLoading?: boolean;
|
|
23
|
-
purchaseButtonText
|
|
24
|
-
processingText
|
|
25
|
-
restoreButtonText
|
|
22
|
+
purchaseButtonText: string;
|
|
23
|
+
processingText: string;
|
|
24
|
+
restoreButtonText: string;
|
|
25
|
+
loadingText: string;
|
|
26
|
+
emptyText: string;
|
|
26
27
|
privacyUrl?: string;
|
|
27
28
|
termsUrl?: string;
|
|
28
29
|
privacyText?: string;
|
|
@@ -57,20 +58,14 @@ export const SubscriptionTabContent: React.FC<SubscriptionTabContentProps> =
|
|
|
57
58
|
purchaseButtonText,
|
|
58
59
|
processingText,
|
|
59
60
|
restoreButtonText,
|
|
61
|
+
loadingText,
|
|
62
|
+
emptyText,
|
|
60
63
|
privacyUrl,
|
|
61
64
|
termsUrl,
|
|
62
65
|
privacyText,
|
|
63
66
|
termsOfServiceText,
|
|
64
67
|
}) => {
|
|
65
68
|
const tokens = useAppDesignTokens();
|
|
66
|
-
const { t } = useLocalization();
|
|
67
|
-
|
|
68
|
-
const displayPurchaseButtonText =
|
|
69
|
-
purchaseButtonText || t("paywall.subscribe");
|
|
70
|
-
const displayProcessingText =
|
|
71
|
-
processingText || t("paywall.processing");
|
|
72
|
-
const displayRestoreButtonText =
|
|
73
|
-
restoreButtonText || t("paywall.restore");
|
|
74
69
|
|
|
75
70
|
const sortedPackages = useMemo(() => sortPackages(packages), [packages]);
|
|
76
71
|
|
|
@@ -86,8 +81,8 @@ export const SubscriptionTabContent: React.FC<SubscriptionTabContentProps> =
|
|
|
86
81
|
isLoading={isLoading}
|
|
87
82
|
selectedPkg={selectedPackage}
|
|
88
83
|
onSelect={onSelectPackage}
|
|
89
|
-
loadingText={
|
|
90
|
-
emptyText={
|
|
84
|
+
loadingText={loadingText}
|
|
85
|
+
emptyText={emptyText}
|
|
91
86
|
/>
|
|
92
87
|
|
|
93
88
|
{features.length > 0 && (
|
|
@@ -103,13 +98,13 @@ export const SubscriptionTabContent: React.FC<SubscriptionTabContentProps> =
|
|
|
103
98
|
</ScrollView>
|
|
104
99
|
|
|
105
100
|
<SubscriptionFooter
|
|
106
|
-
isProcessing={false}
|
|
101
|
+
isProcessing={false}
|
|
107
102
|
isLoading={isLoading}
|
|
108
|
-
processingText={
|
|
109
|
-
purchaseButtonText={
|
|
103
|
+
processingText={processingText}
|
|
104
|
+
purchaseButtonText={purchaseButtonText}
|
|
110
105
|
hasPackages={packages.length > 0}
|
|
111
106
|
selectedPkg={selectedPackage}
|
|
112
|
-
restoreButtonText={
|
|
107
|
+
restoreButtonText={restoreButtonText}
|
|
113
108
|
showRestoreButton={!!onRestore}
|
|
114
109
|
onPurchase={onPurchase}
|
|
115
110
|
onRestore={onRestore || (() => { })}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useCreditChecker Hook
|
|
3
3
|
*
|
|
4
|
-
* Provides credit checking utilities using
|
|
4
|
+
* Provides credit checking utilities using module-level repository.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { useMemo } from "react";
|
|
8
8
|
import type { CreditType } from "../../domain/entities/Credits";
|
|
9
|
-
import {
|
|
9
|
+
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
10
10
|
import {
|
|
11
11
|
createCreditChecker,
|
|
12
12
|
type CreditCheckResult,
|
|
@@ -30,11 +30,11 @@ export interface UseCreditCheckerResult {
|
|
|
30
30
|
export const useCreditChecker = ({
|
|
31
31
|
getCreditType,
|
|
32
32
|
}: UseCreditCheckerParams): UseCreditCheckerResult => {
|
|
33
|
-
const repository =
|
|
33
|
+
const repository = getCreditsRepository();
|
|
34
34
|
|
|
35
35
|
const checker = useMemo(
|
|
36
36
|
() => createCreditChecker({ repository, getCreditType }),
|
|
37
|
-
[
|
|
37
|
+
[getCreditType]
|
|
38
38
|
);
|
|
39
39
|
|
|
40
40
|
return checker;
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
* useCredits Hook
|
|
3
3
|
*
|
|
4
4
|
* TanStack Query hook for fetching user credits.
|
|
5
|
-
* Generic and reusable - uses config from
|
|
5
|
+
* Generic and reusable - uses config from module-level provider.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { useQuery } from "@tanstack/react-query";
|
|
9
9
|
import type { UserCredits, CreditType } from "../../domain/entities/Credits";
|
|
10
10
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "
|
|
11
|
+
getCreditsRepository,
|
|
12
|
+
getCreditsConfig,
|
|
13
|
+
} from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
14
14
|
|
|
15
15
|
const CACHE_CONFIG = {
|
|
16
16
|
staleTime: 30 * 1000,
|
|
@@ -42,8 +42,8 @@ export const useCredits = ({
|
|
|
42
42
|
userId,
|
|
43
43
|
enabled = true,
|
|
44
44
|
}: UseCreditsParams): UseCreditsResult => {
|
|
45
|
-
const repository =
|
|
46
|
-
const config =
|
|
45
|
+
const repository = getCreditsRepository();
|
|
46
|
+
const config = getCreditsConfig();
|
|
47
47
|
|
|
48
48
|
const { data, isLoading, error, refetch } = useQuery({
|
|
49
49
|
queryKey: creditsQueryKeys.user(userId ?? ""),
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* useDeductCredit Hook
|
|
3
3
|
*
|
|
4
4
|
* TanStack Query mutation hook for deducting credits.
|
|
5
|
-
* Generic and reusable - uses
|
|
5
|
+
* Generic and reusable - uses module-level repository.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
9
9
|
import type { CreditType, UserCredits } from "../../domain/entities/Credits";
|
|
10
|
-
import {
|
|
10
|
+
import { getCreditsRepository } from "../../infrastructure/repositories/CreditsRepositoryProvider";
|
|
11
11
|
import { creditsQueryKeys } from "./useCredits";
|
|
12
12
|
|
|
13
13
|
export interface UseDeductCreditParams {
|
|
@@ -24,7 +24,7 @@ export const useDeductCredit = ({
|
|
|
24
24
|
userId,
|
|
25
25
|
onCreditsExhausted,
|
|
26
26
|
}: UseDeductCreditParams): UseDeductCreditResult => {
|
|
27
|
-
const repository =
|
|
27
|
+
const repository = getCreditsRepository();
|
|
28
28
|
const queryClient = useQueryClient();
|
|
29
29
|
|
|
30
30
|
const mutation = useMutation({
|
|
@@ -113,7 +113,7 @@ export interface UseInitializeCreditsResult {
|
|
|
113
113
|
export const useInitializeCredits = ({
|
|
114
114
|
userId,
|
|
115
115
|
}: UseInitializeCreditsParams): UseInitializeCreditsResult => {
|
|
116
|
-
const repository =
|
|
116
|
+
const repository = getCreditsRepository();
|
|
117
117
|
const queryClient = useQueryClient();
|
|
118
118
|
|
|
119
119
|
const mutation = useMutation({
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Credits Context
|
|
3
|
-
*
|
|
4
|
-
* React context for credits configuration.
|
|
5
|
-
* Allows main app to provide credit limits and collection name.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { createContext, useContext } from "react";
|
|
9
|
-
import type { CreditsConfig } from "../../domain/entities/Credits";
|
|
10
|
-
import { DEFAULT_CREDITS_CONFIG } from "../../domain/entities/Credits";
|
|
11
|
-
import type { CreditsRepository } from "../../infrastructure/repositories/CreditsRepository";
|
|
12
|
-
|
|
13
|
-
export interface CreditsContextValue {
|
|
14
|
-
config: CreditsConfig;
|
|
15
|
-
repository: CreditsRepository | null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const CreditsContext = createContext<CreditsContextValue>({
|
|
19
|
-
config: DEFAULT_CREDITS_CONFIG,
|
|
20
|
-
repository: null,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
export const useCreditsContext = (): CreditsContextValue => {
|
|
24
|
-
const context = useContext(CreditsContext);
|
|
25
|
-
if (!context.repository) {
|
|
26
|
-
throw new Error("CreditsProvider must be used to provide credits config");
|
|
27
|
-
}
|
|
28
|
-
return context;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const useCreditsConfig = (): CreditsConfig => {
|
|
32
|
-
const { config } = useContext(CreditsContext);
|
|
33
|
-
return config;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const useCreditsRepository = (): CreditsRepository => {
|
|
37
|
-
const { repository } = useContext(CreditsContext);
|
|
38
|
-
if (!repository) {
|
|
39
|
-
throw new Error("CreditsProvider must be used to provide repository");
|
|
40
|
-
}
|
|
41
|
-
return repository;
|
|
42
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Credits Provider
|
|
3
|
-
*
|
|
4
|
-
* React provider for credits configuration.
|
|
5
|
-
* Main app uses this to configure credit limits.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React, { useMemo } from "react";
|
|
9
|
-
import type { CreditsConfig } from "../../domain/entities/Credits";
|
|
10
|
-
import { DEFAULT_CREDITS_CONFIG } from "../../domain/entities/Credits";
|
|
11
|
-
import {
|
|
12
|
-
CreditsContext,
|
|
13
|
-
type CreditsContextValue,
|
|
14
|
-
} from "../context/CreditsContext";
|
|
15
|
-
import { createCreditsRepository } from "../../infrastructure/repositories/CreditsRepository";
|
|
16
|
-
|
|
17
|
-
export interface CreditsProviderProps {
|
|
18
|
-
children: React.ReactNode;
|
|
19
|
-
config?: Partial<CreditsConfig>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const CreditsProvider: React.FC<CreditsProviderProps> = ({
|
|
23
|
-
children,
|
|
24
|
-
config,
|
|
25
|
-
}) => {
|
|
26
|
-
const value = useMemo<CreditsContextValue>(() => {
|
|
27
|
-
const mergedConfig: CreditsConfig = {
|
|
28
|
-
...DEFAULT_CREDITS_CONFIG,
|
|
29
|
-
...config,
|
|
30
|
-
};
|
|
31
|
-
const repository = createCreditsRepository(mergedConfig);
|
|
32
|
-
return { config: mergedConfig, repository };
|
|
33
|
-
}, [config]);
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<CreditsContext.Provider value={value}>{children}</CreditsContext.Provider>
|
|
37
|
-
);
|
|
38
|
-
};
|