@umituz/react-native-subscription 1.8.0 → 1.8.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-subscription",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "Subscription management, 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
@@ -231,3 +231,20 @@ export {
231
231
  type UsePremiumWithCreditsParams,
232
232
  type UsePremiumWithCreditsResult,
233
233
  } from "./presentation/hooks/usePremiumWithCredits";
234
+
235
+ export {
236
+ useCreditChecker,
237
+ type UseCreditCheckerParams,
238
+ type UseCreditCheckerResult,
239
+ } from "./presentation/hooks/useCreditChecker";
240
+
241
+ // =============================================================================
242
+ // CREDITS SYSTEM - Utilities
243
+ // =============================================================================
244
+
245
+ export {
246
+ createCreditChecker,
247
+ type CreditCheckResult,
248
+ type CreditCheckerConfig,
249
+ type CreditChecker,
250
+ } from "./utils/creditChecker";
@@ -0,0 +1,41 @@
1
+ /**
2
+ * useCreditChecker Hook
3
+ *
4
+ * Provides credit checking utilities using context repository.
5
+ */
6
+
7
+ import { useMemo } from "react";
8
+ import type { CreditType } from "../../domain/entities/Credits";
9
+ import { useCreditsRepository } from "../context/CreditsContext";
10
+ import {
11
+ createCreditChecker,
12
+ type CreditCheckResult,
13
+ } from "../../utils/creditChecker";
14
+
15
+ export interface UseCreditCheckerParams {
16
+ getCreditType: (operationType: string) => CreditType;
17
+ }
18
+
19
+ export interface UseCreditCheckerResult {
20
+ checkCreditsAvailable: (
21
+ userId: string | undefined,
22
+ operationType: string
23
+ ) => Promise<CreditCheckResult>;
24
+ deductCreditsAfterSuccess: (
25
+ userId: string | undefined,
26
+ creditType: CreditType
27
+ ) => Promise<void>;
28
+ }
29
+
30
+ export const useCreditChecker = ({
31
+ getCreditType,
32
+ }: UseCreditCheckerParams): UseCreditCheckerResult => {
33
+ const repository = useCreditsRepository();
34
+
35
+ const checker = useMemo(
36
+ () => createCreditChecker({ repository, getCreditType }),
37
+ [repository, getCreditType]
38
+ );
39
+
40
+ return checker;
41
+ };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Credit Checker Utility
3
+ *
4
+ * Validates credit availability before operations.
5
+ * Generic - works with any generation type mapping.
6
+ */
7
+
8
+ import type { CreditType } from "../domain/entities/Credits";
9
+ import type { CreditsRepository } from "../infrastructure/repositories/CreditsRepository";
10
+
11
+ export interface CreditCheckResult {
12
+ success: boolean;
13
+ error?: string;
14
+ creditType?: CreditType;
15
+ }
16
+
17
+ export interface CreditCheckerConfig {
18
+ repository: CreditsRepository;
19
+ getCreditType: (operationType: string) => CreditType;
20
+ }
21
+
22
+ export const createCreditChecker = (config: CreditCheckerConfig) => {
23
+ const { repository, getCreditType } = config;
24
+
25
+ const checkCreditsAvailable = async (
26
+ userId: string | undefined,
27
+ operationType: string
28
+ ): Promise<CreditCheckResult> => {
29
+ if (!userId) {
30
+ return { success: false, error: "anonymous_user_blocked" };
31
+ }
32
+
33
+ const creditType = getCreditType(operationType);
34
+ const hasCreditsAvailable = await repository.hasCredits(userId, creditType);
35
+
36
+ if (!hasCreditsAvailable) {
37
+ return {
38
+ success: false,
39
+ error:
40
+ creditType === "image"
41
+ ? "credits_exhausted_image"
42
+ : "credits_exhausted_text",
43
+ creditType,
44
+ };
45
+ }
46
+
47
+ return { success: true, creditType };
48
+ };
49
+
50
+ const deductCreditsAfterSuccess = async (
51
+ userId: string | undefined,
52
+ creditType: CreditType
53
+ ): Promise<void> => {
54
+ if (!userId) return;
55
+
56
+ const maxRetries = 3;
57
+ let lastError: Error | null = null;
58
+
59
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
60
+ const result = await repository.deductCredit(userId, creditType);
61
+ if (result.success) {
62
+ return;
63
+ }
64
+ lastError = new Error(result.error?.message || "Deduction failed");
65
+ await new Promise((r) => setTimeout(r, 500 * (attempt + 1)));
66
+ }
67
+
68
+ if (lastError) {
69
+ throw lastError;
70
+ }
71
+ };
72
+
73
+ return {
74
+ checkCreditsAvailable,
75
+ deductCreditsAfterSuccess,
76
+ };
77
+ };
78
+
79
+ export type CreditChecker = ReturnType<typeof createCreditChecker>;