@umituz/react-native-ai-generation-content 1.57.3 → 1.58.0

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-ai-generation-content",
3
- "version": "1.57.3",
3
+ "version": "1.58.0",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -19,6 +19,7 @@
19
19
  */
20
20
 
21
21
  import { useCallback, useMemo } from "react";
22
+ import { useOffline } from "@umituz/react-native-design-system";
22
23
  import { useAuth, useAuthModalStore } from "@umituz/react-native-auth";
23
24
  import {
24
25
  usePremium,
@@ -41,7 +42,10 @@ import type {
41
42
  export function useAIFeatureGate(
42
43
  options: AIFeatureGateOptions,
43
44
  ): AIFeatureGateReturn {
44
- const { creditCost, onSuccess, onError } = options;
45
+ const { creditCost, onNetworkError, onSuccess, onError } = options;
46
+
47
+ // Network state
48
+ const { isOffline } = useOffline();
45
49
 
46
50
  // Auth state
47
51
  const { isAuthenticated: rawIsAuthenticated, isAnonymous } = useAuth();
@@ -69,16 +73,23 @@ export function useAIFeatureGate(
69
73
  isCreditsLoaded,
70
74
  });
71
75
 
72
- // Can access if: authenticated AND (premium OR has credits)
76
+ // Can access if: online AND authenticated AND (premium OR has credits)
73
77
  const canAccess = useMemo(() => {
78
+ if (isOffline) return false;
74
79
  if (!isAuthenticated) return false;
75
80
  if (isPremium) return true;
76
81
  return hasCredits;
77
- }, [isAuthenticated, isPremium, hasCredits]);
82
+ }, [isOffline, isAuthenticated, isPremium, hasCredits]);
78
83
 
79
- // Wrapped requireFeature with optional callbacks
84
+ // Wrapped requireFeature with offline check and optional callbacks
80
85
  const requireFeature = useCallback(
81
86
  (action: () => void | Promise<void>): void => {
87
+ // Network check first - must be online
88
+ if (isOffline) {
89
+ onNetworkError?.();
90
+ return;
91
+ }
92
+ // Then auth/credit checks via subscription package
82
93
  requireFeatureFromPackage(() => {
83
94
  const result = action();
84
95
  if (result instanceof Promise) {
@@ -94,7 +105,7 @@ export function useAIFeatureGate(
94
105
  }
95
106
  });
96
107
  },
97
- [requireFeatureFromPackage, onSuccess, onError],
108
+ [isOffline, onNetworkError, requireFeatureFromPackage, onSuccess, onError],
98
109
  );
99
110
 
100
111
  return {
@@ -105,5 +116,6 @@ export function useAIFeatureGate(
105
116
  isAuthenticated,
106
117
  isPremium,
107
118
  creditBalance,
119
+ isOffline,
108
120
  };
109
121
  }
@@ -14,6 +14,11 @@ export interface AIFeatureGateOptions {
14
14
  */
15
15
  featureName?: string;
16
16
 
17
+ /**
18
+ * Callback fired when network is unavailable
19
+ */
20
+ onNetworkError?: () => void;
21
+
17
22
  /**
18
23
  * Callback fired when feature is successfully accessed and executed
19
24
  */
@@ -61,6 +66,11 @@ export interface AIFeatureGateReturn {
61
66
  * Current credit balance
62
67
  */
63
68
  creditBalance: number;
69
+
70
+ /**
71
+ * Whether device is offline
72
+ */
73
+ isOffline: boolean;
64
74
  }
65
75
 
66
76
  /**
@@ -9,22 +9,8 @@ export interface BaseWizardFlowProps {
9
9
  readonly model: string;
10
10
  /** User ID for saving creations */
11
11
  readonly userId?: string;
12
- /** Is user authenticated (registered, not anonymous) */
13
- readonly isAuthenticated: boolean;
14
- /** Does user have premium subscription */
15
- readonly hasPremium: boolean;
16
- /** User's credit balance */
17
- readonly creditBalance: number;
18
- /** Are credits loaded */
19
- readonly isCreditsLoaded: boolean;
20
12
  /** Credit cost for this generation - REQUIRED, determined by the app */
21
13
  readonly creditCost: number;
22
- /** Is device offline - prevents generation when true */
23
- readonly isOffline?: boolean;
24
- /** Show auth modal with callback */
25
- readonly onShowAuthModal: (callback: () => void) => void;
26
- /** Show paywall */
27
- readonly onShowPaywall: () => void;
28
14
  /** Called when network is unavailable and generation is blocked */
29
15
  readonly onNetworkError?: () => void;
30
16
  /** Called when generation completes */
@@ -8,6 +8,7 @@ import { View, StyleSheet } from "react-native";
8
8
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
9
9
  import { GenericWizardFlow } from "../../../../domains/generation/wizard/presentation/components";
10
10
  import { IMAGE_TO_VIDEO_WIZARD_CONFIG } from "../../../../domains/generation/wizard/configs";
11
+ import { useAIFeatureGate } from "../../../../domains/access-control";
11
12
  import type { WizardScenarioData } from "../../../../domains/generation/wizard/presentation/hooks/useWizardGeneration";
12
13
  import type { BaseWizardFlowProps } from "../../../../domains/generation/wizard/presentation/components/WizardFlow.types";
13
14
  import type { AlertMessages } from "../../../../presentation/hooks/generation/types";
@@ -29,14 +30,7 @@ export const ImageToVideoWizardFlow: React.FC<ImageToVideoWizardFlowProps> = (pr
29
30
  const {
30
31
  model,
31
32
  userId,
32
- isAuthenticated,
33
- hasPremium,
34
- creditBalance,
35
- isCreditsLoaded,
36
33
  creditCost,
37
- isOffline,
38
- onShowAuthModal,
39
- onShowPaywall,
40
34
  onNetworkError,
41
35
  onGenerationComplete,
42
36
  onGenerationError,
@@ -47,6 +41,12 @@ export const ImageToVideoWizardFlow: React.FC<ImageToVideoWizardFlowProps> = (pr
47
41
 
48
42
  const tokens = useAppDesignTokens();
49
43
 
44
+ // Centralized access control - handles offline, auth, credits, paywall
45
+ const { requireFeature } = useAIFeatureGate({
46
+ creditCost,
47
+ onNetworkError,
48
+ });
49
+
50
50
  const scenario: WizardScenarioData = useMemo(
51
51
  () => ({
52
52
  id: "image-to-video",
@@ -71,15 +71,10 @@ export const ImageToVideoWizardFlow: React.FC<ImageToVideoWizardFlowProps> = (pr
71
71
 
72
72
  const handleGenerationStart = useCallback(
73
73
  (_data: Record<string, unknown>, proceed: () => void) => {
74
- // Network check - must be online to generate
75
- if (isOffline) { onNetworkError?.(); return; }
76
- // Auth check - must be authenticated
77
- if (!isAuthenticated) { onShowAuthModal(proceed); return; }
78
- // Credit check - must have enough credits
79
- if (!hasPremium && isCreditsLoaded && creditBalance < creditCost) { onShowPaywall(); return; }
80
- proceed();
74
+ // Use centralized access control - checks offline, auth, credits
75
+ requireFeature(proceed);
81
76
  },
82
- [isOffline, isAuthenticated, hasPremium, creditBalance, creditCost, isCreditsLoaded, onNetworkError, onShowAuthModal, onShowPaywall],
77
+ [requireFeature],
83
78
  );
84
79
 
85
80
  const handleGenerationComplete = useCallback(() => {
@@ -99,7 +94,6 @@ export const ImageToVideoWizardFlow: React.FC<ImageToVideoWizardFlowProps> = (pr
99
94
  onGenerationStart={handleGenerationStart}
100
95
  onGenerationComplete={handleGenerationComplete}
101
96
  onGenerationError={onGenerationError}
102
- onCreditsExhausted={onShowPaywall}
103
97
  onBack={onBack}
104
98
  onTryAgain={onBack}
105
99
  t={t}
@@ -8,6 +8,7 @@ import { View, StyleSheet } from "react-native";
8
8
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
9
9
  import { GenericWizardFlow } from "../../../../domains/generation/wizard/presentation/components";
10
10
  import { TEXT_TO_IMAGE_WIZARD_CONFIG } from "../../../../domains/generation/wizard/configs";
11
+ import { useAIFeatureGate } from "../../../../domains/access-control";
11
12
  import type { WizardScenarioData } from "../../../../domains/generation/wizard/presentation/hooks/useWizardGeneration";
12
13
  import type { BaseWizardFlowProps } from "../../../../domains/generation/wizard/presentation/components/WizardFlow.types";
13
14
  import type { AlertMessages } from "../../../../presentation/hooks/generation/types";
@@ -29,14 +30,7 @@ export const TextToImageWizardFlow: React.FC<TextToImageWizardFlowProps> = (prop
29
30
  const {
30
31
  model,
31
32
  userId,
32
- isAuthenticated,
33
- hasPremium,
34
- creditBalance,
35
- isCreditsLoaded,
36
33
  creditCost,
37
- isOffline,
38
- onShowAuthModal,
39
- onShowPaywall,
40
34
  onNetworkError,
41
35
  onGenerationComplete,
42
36
  onGenerationError,
@@ -47,6 +41,12 @@ export const TextToImageWizardFlow: React.FC<TextToImageWizardFlowProps> = (prop
47
41
 
48
42
  const tokens = useAppDesignTokens();
49
43
 
44
+ // Centralized access control - handles offline, auth, credits, paywall
45
+ const { requireFeature } = useAIFeatureGate({
46
+ creditCost,
47
+ onNetworkError,
48
+ });
49
+
50
50
  const scenario: WizardScenarioData = useMemo(
51
51
  () => ({
52
52
  id: "text-to-image",
@@ -71,15 +71,10 @@ export const TextToImageWizardFlow: React.FC<TextToImageWizardFlowProps> = (prop
71
71
 
72
72
  const handleGenerationStart = useCallback(
73
73
  (_data: Record<string, unknown>, proceed: () => void) => {
74
- // Network check - must be online to generate
75
- if (isOffline) { onNetworkError?.(); return; }
76
- // Auth check - must be authenticated
77
- if (!isAuthenticated) { onShowAuthModal(proceed); return; }
78
- // Credit check - must have enough credits
79
- if (!hasPremium && isCreditsLoaded && creditBalance < creditCost) { onShowPaywall(); return; }
80
- proceed();
74
+ // Use centralized access control - checks offline, auth, credits
75
+ requireFeature(proceed);
81
76
  },
82
- [isOffline, isAuthenticated, hasPremium, creditBalance, creditCost, isCreditsLoaded, onNetworkError, onShowAuthModal, onShowPaywall],
77
+ [requireFeature],
83
78
  );
84
79
 
85
80
  const handleGenerationComplete = useCallback(() => {
@@ -99,7 +94,6 @@ export const TextToImageWizardFlow: React.FC<TextToImageWizardFlowProps> = (prop
99
94
  onGenerationStart={handleGenerationStart}
100
95
  onGenerationComplete={handleGenerationComplete}
101
96
  onGenerationError={onGenerationError}
102
- onCreditsExhausted={onShowPaywall}
103
97
  onBack={onBack}
104
98
  onTryAgain={onBack}
105
99
  t={t}
@@ -8,6 +8,7 @@ import { View, StyleSheet } from "react-native";
8
8
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
9
9
  import { GenericWizardFlow } from "../../../../domains/generation/wizard/presentation/components";
10
10
  import { TEXT_TO_VIDEO_WIZARD_CONFIG } from "../../../../domains/generation/wizard/configs";
11
+ import { useAIFeatureGate } from "../../../../domains/access-control";
11
12
  import type { WizardScenarioData } from "../../../../domains/generation/wizard/presentation/hooks/useWizardGeneration";
12
13
  import type { BaseWizardFlowProps } from "../../../../domains/generation/wizard/presentation/components/WizardFlow.types";
13
14
  import type { AlertMessages } from "../../../../presentation/hooks/generation/types";
@@ -29,14 +30,7 @@ export const TextToVideoWizardFlow: React.FC<TextToVideoWizardFlowProps> = (prop
29
30
  const {
30
31
  model,
31
32
  userId,
32
- isAuthenticated,
33
- hasPremium,
34
- creditBalance,
35
- isCreditsLoaded,
36
33
  creditCost,
37
- isOffline,
38
- onShowAuthModal,
39
- onShowPaywall,
40
34
  onNetworkError,
41
35
  onGenerationComplete,
42
36
  onGenerationError,
@@ -47,6 +41,12 @@ export const TextToVideoWizardFlow: React.FC<TextToVideoWizardFlowProps> = (prop
47
41
 
48
42
  const tokens = useAppDesignTokens();
49
43
 
44
+ // Centralized access control - handles offline, auth, credits, paywall
45
+ const { requireFeature } = useAIFeatureGate({
46
+ creditCost,
47
+ onNetworkError,
48
+ });
49
+
50
50
  const scenario: WizardScenarioData = useMemo(
51
51
  () => ({
52
52
  id: "text-to-video",
@@ -71,15 +71,10 @@ export const TextToVideoWizardFlow: React.FC<TextToVideoWizardFlowProps> = (prop
71
71
 
72
72
  const handleGenerationStart = useCallback(
73
73
  (_data: Record<string, unknown>, proceed: () => void) => {
74
- // Network check - must be online to generate
75
- if (isOffline) { onNetworkError?.(); return; }
76
- // Auth check - must be authenticated
77
- if (!isAuthenticated) { onShowAuthModal(proceed); return; }
78
- // Credit check - must have enough credits
79
- if (!hasPremium && isCreditsLoaded && creditBalance < creditCost) { onShowPaywall(); return; }
80
- proceed();
74
+ // Use centralized access control - checks offline, auth, credits
75
+ requireFeature(proceed);
81
76
  },
82
- [isOffline, isAuthenticated, hasPremium, creditBalance, creditCost, isCreditsLoaded, onNetworkError, onShowAuthModal, onShowPaywall],
77
+ [requireFeature],
83
78
  );
84
79
 
85
80
  const handleGenerationComplete = useCallback(() => {
@@ -99,7 +94,6 @@ export const TextToVideoWizardFlow: React.FC<TextToVideoWizardFlowProps> = (prop
99
94
  onGenerationStart={handleGenerationStart}
100
95
  onGenerationComplete={handleGenerationComplete}
101
96
  onGenerationError={onGenerationError}
102
- onCreditsExhausted={onShowPaywall}
103
97
  onBack={onBack}
104
98
  onTryAgain={onBack}
105
99
  t={t}