@umituz/react-native-ai-generation-content 1.90.2 → 1.90.4

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 (171) hide show
  1. package/package.json +3 -3
  2. package/src/domain/interfaces/app-services-auth.interface.ts +27 -0
  3. package/src/domain/interfaces/app-services-composite.interface.ts +29 -0
  4. package/src/domain/interfaces/app-services-optional.interface.ts +42 -0
  5. package/src/domain/interfaces/app-services.interface.ts +0 -79
  6. package/src/domain/interfaces/index.ts +3 -0
  7. package/src/domains/background/infrastructure/services/job-poller-index.ts +7 -0
  8. package/src/domains/background/infrastructure/services/job-poller-utils.ts +127 -0
  9. package/src/domains/background/infrastructure/services/job-poller.service.ts +85 -140
  10. package/src/domains/background/infrastructure/utils/polling-interval.util.ts +1 -1
  11. package/src/domains/background/presentation/hooks/use-background-generation.ts +1 -1
  12. package/src/domains/content-moderation/index.ts +7 -13
  13. package/src/domains/content-moderation/infrastructure/services/content-moderation.service.ts +1 -1
  14. package/src/domains/content-moderation/infrastructure/services/moderators/image.moderator.ts +34 -8
  15. package/src/domains/content-moderation/infrastructure/services/moderators/text.moderator.ts +15 -4
  16. package/src/domains/content-moderation/infrastructure/services/moderators/video.moderator.ts +34 -8
  17. package/src/domains/content-moderation/infrastructure/services/moderators/voice.moderator.ts +19 -8
  18. package/src/domains/content-moderation/infrastructure/services/pattern-matcher.service.ts +1 -2
  19. package/src/domains/creations/domain/types/creation-categories.constants.ts +57 -0
  20. package/src/domains/creations/domain/types/creation-categories.helpers.ts +67 -0
  21. package/src/domains/creations/domain/types/creation-categories.ts +7 -114
  22. package/src/domains/creations/domain/utils/creation-display.util.ts +1 -1
  23. package/src/domains/creations/domain/utils/status-helpers.ts +1 -1
  24. package/src/domains/creations/presentation/hooks/creation-validators.ts +31 -29
  25. package/src/domains/creations/presentation/hooks/job-poller-index.ts +10 -0
  26. package/src/domains/creations/presentation/hooks/job-poller-utils.filters.ts +34 -0
  27. package/src/domains/creations/presentation/hooks/job-poller-utils.logger.ts +76 -0
  28. package/src/domains/creations/presentation/hooks/job-poller-utils.stale-handlers.ts +52 -0
  29. package/src/domains/creations/presentation/hooks/job-poller-utils.ts +8 -0
  30. package/src/domains/creations/presentation/hooks/useCreations.ts +1 -1
  31. package/src/domains/creations/presentation/hooks/useProcessingJobsPoller.ts +18 -235
  32. package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +1 -2
  33. package/src/domains/creations/presentation-exports.ts +2 -2
  34. package/src/domains/face-detection/domain/entities/FaceDetection.ts +4 -3
  35. package/src/domains/face-detection/presentation/hooks/useFaceDetection.ts +24 -21
  36. package/src/domains/generation/infrastructure/appearance-analysis/index.ts +5 -0
  37. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-preparation.ts +58 -0
  38. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-prompt.ts +69 -0
  39. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-resolution.ts +77 -0
  40. package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple.ts +54 -0
  41. package/src/domains/generation/infrastructure/couple-generation-builder/builder-index.ts +8 -0
  42. package/src/domains/generation/infrastructure/couple-generation-builder/builder-scenario.ts +112 -0
  43. package/src/domains/generation/infrastructure/couple-generation-builder/builder.ts +7 -0
  44. package/src/domains/generation/infrastructure/couple-generation-builder/index.ts +20 -0
  45. package/src/domains/generation/infrastructure/couple-generation-builder/types.ts +44 -0
  46. package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-end-logger.ts +18 -0
  47. package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-start-logger.ts +57 -0
  48. package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-step-logger.ts +106 -0
  49. package/src/domains/generation/infrastructure/couple-generation-builder/utils/index.ts +8 -0
  50. package/src/domains/generation/infrastructure/couple-generation-builder/utils/types.ts +49 -0
  51. package/src/domains/generation/infrastructure/couple-generation-builder/utils.ts +8 -0
  52. package/src/domains/generation/infrastructure/flow/flow-store-actions.ts +105 -0
  53. package/src/domains/generation/infrastructure/flow/flow-store-initial-state.ts +26 -0
  54. package/src/domains/generation/infrastructure/flow/useFlowStore.ts +4 -116
  55. package/src/domains/generation/presentation/useAIGeneration.hook.ts +1 -1
  56. package/src/domains/generation/wizard/infrastructure/strategies/image-generation-strategy-index.ts +7 -0
  57. package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.ts +2 -12
  58. package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.types.ts +11 -0
  59. package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.utils.ts +12 -0
  60. package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts +1 -220
  61. package/src/domains/generation/wizard/infrastructure/strategies/image-input-builder.ts +66 -0
  62. package/src/domains/generation/wizard/infrastructure/strategies/image-input-extraction.ts +88 -0
  63. package/src/domains/generation/wizard/infrastructure/strategies/image-input-prompt-builder.ts +74 -0
  64. package/src/domains/generation/wizard/infrastructure/strategies/image-input-style-enhancements.ts +35 -0
  65. package/src/domains/generation/wizard/infrastructure/strategies/image-strategy-factory.ts +41 -0
  66. package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor-index.ts +10 -0
  67. package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor.ts +76 -0
  68. package/src/domains/generation/wizard/infrastructure/strategies/video-generation-input-builder.ts +46 -0
  69. package/src/domains/generation/wizard/infrastructure/strategies/video-generation-result-types.ts +17 -0
  70. package/src/domains/generation/wizard/infrastructure/strategies/video-generation-submission.ts +61 -0
  71. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.audio-extractor.ts +27 -0
  72. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.executor.ts +2 -176
  73. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.input-builder.ts +90 -0
  74. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.strategy.ts +3 -108
  75. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.types.ts +0 -130
  76. package/src/domains/generation/wizard/infrastructure/strategies/video-generation.validation.ts +136 -0
  77. package/src/domains/generation/wizard/presentation/hooks/photo-upload/index.ts +40 -0
  78. package/src/domains/generation/wizard/presentation/hooks/photo-upload/types.ts +37 -0
  79. package/src/domains/generation/wizard/presentation/hooks/photo-upload/usePhotoUploadStateLogic.ts +142 -0
  80. package/src/domains/generation/wizard/presentation/hooks/use-video-queue-utils.ts +102 -0
  81. package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.handlers.ts +97 -0
  82. package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.saver.ts +54 -0
  83. package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.ts +22 -87
  84. package/src/domains/generation/wizard/presentation/hooks/usePhotoUploadState.ts +8 -177
  85. package/src/domains/generation/wizard/presentation/hooks/useVideoQueueGeneration.ts +1 -295
  86. package/src/domains/generation/wizard/presentation/hooks/useWizardGeneration.ts +1 -1
  87. package/src/domains/generation/wizard/presentation/hooks/video-queue/index.ts +77 -0
  88. package/src/domains/generation/wizard/presentation/hooks/video-queue/use-video-queue-utils.ts +123 -0
  89. package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationCallbacks.ts +119 -0
  90. package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationPolling.ts +75 -0
  91. package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationRefs.ts +65 -0
  92. package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationStart.ts +123 -0
  93. package/src/domains/generation/wizard/presentation/hooks/video-queue-index.ts +9 -0
  94. package/src/domains/image-to-video/domain/types/image-to-video-state.types.ts +11 -4
  95. package/src/domains/text-to-image/domain/constants/index.ts +5 -6
  96. package/src/domains/text-to-image/domain/types/text-to-image.types.ts +43 -22
  97. package/src/domains/text-to-video/domain/types/request.types.ts +32 -9
  98. package/src/domains/text-to-video/domain/types/state.types.ts +22 -22
  99. package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.handlers.ts +44 -0
  100. package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.ts +5 -51
  101. package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.types.ts +33 -0
  102. package/src/exports/features.ts +1 -1
  103. package/src/infrastructure/services/generation-orchestrator.service.ts +2 -2
  104. package/src/infrastructure/utils/couple-input-context.ts +13 -0
  105. package/src/infrastructure/utils/couple-input-index.ts +9 -0
  106. package/src/infrastructure/utils/couple-input-photorealistic.ts +40 -0
  107. package/src/infrastructure/utils/couple-input-refiner.ts +101 -0
  108. package/src/infrastructure/utils/couple-input-resolver.ts +71 -0
  109. package/src/infrastructure/utils/couple-input-types.ts +11 -0
  110. package/src/infrastructure/utils/couple-input.util.ts +3 -176
  111. package/src/infrastructure/utils/photo-generation/photo-preparation.util.ts +1 -1
  112. package/src/infrastructure/validation/base-validator.ts +3 -26
  113. package/src/infrastructure/validation/base-validator.types.ts +32 -0
  114. package/src/presentation/hooks/generation/index.ts +1 -1
  115. package/src/presentation/hooks/generation/orchestrator-abort-logs.ts +48 -0
  116. package/src/presentation/hooks/generation/orchestrator-execution-logs.ts +67 -0
  117. package/src/presentation/hooks/generation/orchestrator-index.ts +14 -0
  118. package/src/presentation/hooks/generation/orchestrator-start-logs.ts +65 -0
  119. package/src/presentation/hooks/generation/orchestrator-state-utils.ts +17 -0
  120. package/src/presentation/hooks/generation/orchestrator-types.ts +55 -0
  121. package/src/presentation/hooks/generation/orchestrator-utils-index.ts +29 -0
  122. package/src/presentation/hooks/generation/orchestrator-utils.ts +25 -0
  123. package/src/presentation/hooks/generation/useDualImageGeneration.ts +1 -1
  124. package/src/presentation/hooks/generation/useImageGeneration.ts +1 -1
  125. package/src/presentation/hooks/generation/useVideoGeneration.ts +1 -1
  126. package/src/shared/hooks/factories/generation-hook-index.ts +12 -0
  127. package/src/shared/hooks/factories/generation-hook-types.ts +47 -0
  128. package/src/shared/hooks/factories/generation-hook-utils.ts +94 -0
  129. package/src/shared/hooks/factories/index.ts +1 -1
  130. package/src/shared/index.ts +1 -1
  131. package/src/shared/utils/calculations/aspect-ratio-calculations.ts +30 -0
  132. package/src/shared/utils/calculations/base64-calculations.ts +26 -0
  133. package/src/shared/utils/calculations/confidence-calculations.ts +21 -0
  134. package/src/shared/utils/calculations/cost-calculations-index.ts +43 -0
  135. package/src/shared/utils/calculations/cost-calculations.ts +25 -0
  136. package/src/shared/utils/calculations/credit-calculations.ts +37 -0
  137. package/src/shared/utils/calculations/index.ts +46 -0
  138. package/src/shared/utils/calculations/math-utilities.ts +32 -0
  139. package/src/shared/utils/calculations/memory-calculations.ts +33 -0
  140. package/src/shared/utils/calculations/pagination-calculations.ts +38 -0
  141. package/src/shared/utils/calculations/percentage-calculations.ts +33 -0
  142. package/src/shared/utils/calculations/time-calculations.ts +99 -0
  143. package/src/shared/utils/credit.ts +1 -1
  144. package/src/shared-kernel/application/hooks/index.ts +8 -0
  145. package/src/shared-kernel/application/hooks/use-feature-state.ts +106 -0
  146. package/src/shared-kernel/application/hooks/use-generation-handler.ts +110 -0
  147. package/src/shared-kernel/base-types/base-callbacks.types.ts +73 -0
  148. package/src/shared-kernel/base-types/base-feature-state.types.ts +77 -0
  149. package/src/shared-kernel/base-types/base-generation.types.ts +69 -0
  150. package/src/shared-kernel/base-types/index.ts +30 -0
  151. package/src/shared-kernel/domain/base-generation-strategy.ts +146 -0
  152. package/src/shared-kernel/domain/index.ts +7 -0
  153. package/src/shared-kernel/index.ts +17 -0
  154. package/src/shared-kernel/infrastructure/validation/common-validators.ts +126 -0
  155. package/src/shared-kernel/infrastructure/validation/common-validators.types.ts +33 -0
  156. package/src/shared-kernel/infrastructure/validation/error-handler.ts +52 -0
  157. package/src/shared-kernel/infrastructure/validation/error-handler.types.ts +38 -0
  158. package/src/shared-kernel/infrastructure/validation/error-handler.utils.ts +79 -0
  159. package/src/shared-kernel/infrastructure/validation/index.ts +70 -0
  160. package/src/domains/content-moderation/infrastructure/services/index.ts +0 -8
  161. package/src/domains/creations/domain/constants/index.ts +0 -12
  162. package/src/domains/creations/domain/utils/index.ts +0 -12
  163. package/src/domains/generation/infrastructure/couple-generation-builder.ts +0 -374
  164. package/src/domains/image-to-video/domain/index.ts +0 -2
  165. package/src/domains/image-to-video/infrastructure/index.ts +0 -1
  166. package/src/domains/image-to-video/presentation/index.ts +0 -5
  167. package/src/domains/text-to-video/domain/index.ts +0 -1
  168. package/src/domains/text-to-video/presentation/index.ts +0 -7
  169. package/src/presentation/hooks/generation/orchestrator.ts +0 -276
  170. package/src/shared/hooks/factories/createGenerationHook.ts +0 -253
  171. package/src/shared/utils/calculations.util.ts +0 -366
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Generic Photo Upload State Hook - Core Logic
3
+ */
4
+
5
+ import { useCallback, useRef, useEffect } from "react";
6
+ import { useMedia, MediaQuality, MediaValidationError, MEDIA_CONSTANTS } from "@umituz/react-native-design-system/media";
7
+ import type { UploadedImage } from "../../../../presentation/hooks/generation/useAIGenerateState";
8
+ import type { PhotoUploadConfig, PhotoUploadError, PhotoUploadTranslations } from "./types";
9
+
10
+ export function usePhotoUploadStateLogic(
11
+ config: PhotoUploadConfig | undefined,
12
+ translations: PhotoUploadTranslations,
13
+ initialImage: UploadedImage | undefined,
14
+ stepId: string | undefined,
15
+ onError: ((error: PhotoUploadError) => void) | undefined,
16
+ setImage: (image: UploadedImage | null) => void,
17
+ ) {
18
+ const { pickImage, isLoading } = useMedia();
19
+ const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
20
+
21
+ // Use refs to avoid effect re-runs on callback changes
22
+ const onErrorRef = useRef(onError);
23
+ const translationsRef = useRef(translations);
24
+
25
+ useEffect(() => {
26
+ onErrorRef.current = onError;
27
+ translationsRef.current = translations;
28
+ }, [onError, translations]);
29
+
30
+ const maxFileSizeMB = config?.maxFileSizeMB ?? MEDIA_CONSTANTS.MAX_IMAGE_SIZE_MB;
31
+
32
+ useEffect(() => {
33
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
34
+ console.log("[usePhotoUploadState] Step changed, resetting image", { stepId, hasInitialImage: !!initialImage });
35
+ }
36
+ setImage(initialImage || null);
37
+ }, [stepId, initialImage, setImage]);
38
+
39
+ useEffect(() => {
40
+ // Clear any existing timeout first
41
+ if (timeoutRef.current) {
42
+ clearTimeout(timeoutRef.current);
43
+ timeoutRef.current = undefined;
44
+ }
45
+
46
+ if (isLoading) {
47
+ timeoutRef.current = setTimeout(() => {
48
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
49
+ console.warn("[usePhotoUploadState] Image picker timeout - possible stuck state (DEV warning only)");
50
+ }
51
+ // NOTE: Do NOT call onError here — the picker may still complete successfully.
52
+ // Showing a modal alert while the picker is open blocks the UI.
53
+ }, 30000);
54
+ }
55
+
56
+ return () => {
57
+ if (timeoutRef.current) {
58
+ clearTimeout(timeoutRef.current);
59
+ timeoutRef.current = undefined;
60
+ }
61
+ };
62
+ }, [isLoading]);
63
+
64
+ const clearImage = useCallback(() => {
65
+ setImage(null);
66
+ }, [setImage]);
67
+
68
+ const handlePickImage = useCallback(async () => {
69
+ try {
70
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
71
+ console.log("[usePhotoUploadState] Starting image pick");
72
+ }
73
+
74
+ const result = await pickImage({
75
+ allowsEditing: true,
76
+ aspect: [1, 1],
77
+ quality: MediaQuality.MEDIUM,
78
+ maxFileSizeMB,
79
+ });
80
+
81
+ if (result.error) {
82
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
83
+ console.log("[usePhotoUploadState] Validation error", result.error);
84
+ }
85
+
86
+ if (result.error === MediaValidationError.FILE_TOO_LARGE) {
87
+ onErrorRef.current?.({
88
+ title: translationsRef.current.fileTooLarge,
89
+ message: translationsRef.current.maxFileSize.replace("{size}", maxFileSizeMB.toString()),
90
+ });
91
+ } else if (result.error === MediaValidationError.PERMISSION_DENIED) {
92
+ onErrorRef.current?.({
93
+ title: translationsRef.current.error,
94
+ message: translationsRef.current.permissionDenied ?? "Permission to access media library is required",
95
+ });
96
+ }
97
+ return;
98
+ }
99
+
100
+ if (result.canceled || !result.assets || result.assets.length === 0) {
101
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
102
+ console.log("[usePhotoUploadState] Image pick canceled");
103
+ }
104
+ return;
105
+ }
106
+
107
+ const selectedAsset = result.assets[0];
108
+ if (!selectedAsset) {
109
+ return;
110
+ }
111
+
112
+ const uploadedImage: UploadedImage = {
113
+ uri: selectedAsset.uri,
114
+ previewUrl: selectedAsset.uri,
115
+ width: selectedAsset.width,
116
+ height: selectedAsset.height,
117
+ fileSize: selectedAsset.fileSize,
118
+ };
119
+
120
+ setImage(uploadedImage);
121
+
122
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
123
+ const fileSizeMB = (selectedAsset.fileSize ?? 0) / (1024 * 1024);
124
+ console.log("[usePhotoUploadState] Image selected", {
125
+ width: uploadedImage.width,
126
+ height: uploadedImage.height,
127
+ fileSizeMB: fileSizeMB.toFixed(2),
128
+ });
129
+ }
130
+ } catch (error) {
131
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
132
+ console.error("[usePhotoUploadState] Error picking image", error);
133
+ }
134
+ onErrorRef.current?.({
135
+ title: translationsRef.current.error,
136
+ message: translationsRef.current.uploadFailed,
137
+ });
138
+ }
139
+ }, [pickImage, maxFileSizeMB, setImage]);
140
+
141
+ return { handlePickImage, clearImage, isLoading };
142
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Video Queue Generation Hook - Utility Functions
3
+ */
4
+
5
+ import type { GenerationUrls } from "./generation-result.utils";
6
+
7
+ /**
8
+ * Clear polling interval
9
+ */
10
+ export function createClearPolling(
11
+ pollingRef: React.MutableRefObject<ReturnType<typeof setInterval> | null>
12
+ ) {
13
+ return () => {
14
+ if (pollingRef.current) {
15
+ clearInterval(pollingRef.current);
16
+ pollingRef.current = null;
17
+ }
18
+ };
19
+ }
20
+
21
+ /**
22
+ * Reset all refs to initial state
23
+ */
24
+ export function createResetRefs(
25
+ clearPolling: () => void,
26
+ creationIdRef: React.MutableRefObject<string | null>,
27
+ requestIdRef: React.MutableRefObject<string | null>,
28
+ modelRef: React.MutableRefObject<string | null>,
29
+ isGeneratingRef: React.MutableRefObject<boolean>,
30
+ isPollingRef: React.MutableRefObject<boolean>,
31
+ consecutiveErrorsRef: React.MutableRefObject<number>,
32
+ pollStartTimeRef: React.MutableRefObject<number | null>,
33
+ setIsGenerating: (value: boolean) => void
34
+ ) {
35
+ return () => {
36
+ clearPolling();
37
+ creationIdRef.current = null;
38
+ requestIdRef.current = null;
39
+ modelRef.current = null;
40
+ isGeneratingRef.current = false;
41
+ isPollingRef.current = false;
42
+ consecutiveErrorsRef.current = 0;
43
+ pollStartTimeRef.current = null;
44
+ setIsGenerating(false);
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Extract duration, resolution, and aspect ratio from input
50
+ */
51
+ export function extractInputMetadata(input: unknown): {
52
+ duration?: number;
53
+ resolution?: string;
54
+ aspectRatio?: string;
55
+ } {
56
+ const inputData = input as Record<string, unknown>;
57
+ return {
58
+ duration: typeof inputData?.duration === "number" ? inputData.duration : undefined,
59
+ resolution: typeof inputData?.resolution === "string" ? inputData.resolution : undefined,
60
+ aspectRatio: typeof inputData?.aspectRatio === "string" ? inputData.aspectRatio : undefined,
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Validate completion data
66
+ */
67
+ export function validateCompletionData(
68
+ creationId: string | null,
69
+ userId: string | null,
70
+ uri: string
71
+ ): boolean {
72
+ return !!(creationId && userId && uri && uri.trim() !== "");
73
+ }
74
+
75
+ /**
76
+ * Log completion data for debugging
77
+ */
78
+ export function logCompletion(
79
+ creationId: string | null,
80
+ userId: string | null,
81
+ urls: GenerationUrls,
82
+ hasOnSuccess: boolean
83
+ ): void {
84
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
85
+ console.log("[VideoQueue] ✅ handleComplete called", {
86
+ creationId,
87
+ userId,
88
+ hasVideoUrl: !!urls.videoUrl,
89
+ hasImageUrl: !!urls.imageUrl,
90
+ hasOnSuccess,
91
+ });
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Log error for debugging
97
+ */
98
+ export function logError(message: string, data: Record<string, unknown>): void {
99
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
100
+ console.error("[VideoQueue] ❌", message, data);
101
+ }
102
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * usePhotoBlockingGeneration Handlers
3
+ * Success and error handlers for photo blocking generation
4
+ */
5
+
6
+ import type { CreationPersistence } from "../../infrastructure/utils/creation-persistence.util";
7
+
8
+ interface HandleSuccessProps {
9
+ readonly creationIdRef: React.MutableRefObject<string | null>;
10
+ readonly userId: string | undefined;
11
+ readonly persistence: CreationPersistence;
12
+ readonly deductCredits?: (cost: number) => Promise<boolean>;
13
+ readonly creditCost?: number;
14
+ readonly onSuccess?: (result: unknown) => void;
15
+ readonly onCreditsExhausted?: () => void;
16
+ }
17
+
18
+ interface HandleErrorProps {
19
+ readonly creationIdRef: React.MutableRefObject<string | null>;
20
+ readonly userId: string | undefined;
21
+ readonly persistence: CreationPersistence;
22
+ readonly onError?: (error: string) => void;
23
+ }
24
+
25
+ export function createSuccessHandler(props: HandleSuccessProps) {
26
+ const {
27
+ creationIdRef,
28
+ userId,
29
+ persistence,
30
+ deductCredits,
31
+ creditCost,
32
+ onSuccess,
33
+ onCreditsExhausted,
34
+ } = props;
35
+
36
+ return async (result: unknown) => {
37
+ const typedResult = result as { imageUrl?: string; videoUrl?: string; audioUrl?: string; logSessionId?: string };
38
+ const creationId = creationIdRef.current;
39
+ const resultUri = typedResult.imageUrl || typedResult.videoUrl || typedResult.audioUrl;
40
+
41
+ if (creationId && userId && resultUri) {
42
+ try {
43
+ await persistence.updateToCompleted(userId, creationId, {
44
+ uri: resultUri,
45
+ imageUrl: typedResult.imageUrl,
46
+ videoUrl: typedResult.videoUrl,
47
+ audioUrl: typedResult.audioUrl,
48
+ logSessionId: typedResult.logSessionId,
49
+ });
50
+ } catch (err) {
51
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
52
+ console.error("[PhotoBlockingGeneration] updateToCompleted error:", err);
53
+ }
54
+ }
55
+ }
56
+
57
+ creationIdRef.current = null;
58
+
59
+ // Deduct credits after successful generation
60
+ if (deductCredits && creditCost) {
61
+ try {
62
+ const deducted = await deductCredits(creditCost);
63
+ if (!deducted) {
64
+ onCreditsExhausted?.();
65
+ }
66
+ } catch (err) {
67
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
68
+ console.error("[PhotoBlockingGeneration] deductCredits error:", err);
69
+ }
70
+ }
71
+ }
72
+
73
+ onSuccess?.(result);
74
+ };
75
+ }
76
+
77
+ export function createErrorHandler(props: HandleErrorProps) {
78
+ const { creationIdRef, userId, persistence, onError } = props;
79
+
80
+ return async (err: { message: string; originalError?: Error & { logSessionId?: string } }) => {
81
+ const creationId = creationIdRef.current;
82
+ const logSessionId = err.originalError?.logSessionId;
83
+
84
+ if (creationId && userId) {
85
+ try {
86
+ await persistence.updateToFailed(userId, creationId, err.message, logSessionId);
87
+ } catch (updateErr) {
88
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
89
+ console.error("[PhotoBlockingGeneration] updateToFailed error:", updateErr);
90
+ }
91
+ }
92
+ }
93
+
94
+ creationIdRef.current = null;
95
+ onError?.(err.message);
96
+ };
97
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * usePhotoBlockingGeneration Saver
3
+ * Handles saving creation to processing state
4
+ */
5
+
6
+ import type { CreationPersistence } from "../../infrastructure/utils/creation-persistence.util";
7
+ import type { WizardScenarioData } from "./wizard-generation.types";
8
+
9
+ interface SaveCreationProps {
10
+ readonly userId: string | undefined;
11
+ readonly scenario: WizardScenarioData;
12
+ readonly persistence: CreationPersistence;
13
+ readonly creditCost?: number;
14
+ readonly creationIdRef: React.MutableRefObject<string | null>;
15
+ }
16
+
17
+ export async function saveCreationToProcessing(
18
+ props: SaveCreationProps,
19
+ input: unknown,
20
+ prompt: string,
21
+ ): Promise<void> {
22
+ const { userId, scenario, persistence, creditCost, creationIdRef } = props;
23
+
24
+ if (!userId || !prompt) return;
25
+
26
+ try {
27
+ // Extract generation parameters from input (for image generation, no duration/resolution)
28
+ const inputData = input as Record<string, unknown>;
29
+ const duration = typeof inputData?.duration === "number" ? inputData.duration : undefined;
30
+ const resolution = typeof inputData?.resolution === "string" ? inputData.resolution : undefined;
31
+ const aspectRatio = typeof inputData?.aspectRatio === "string" ? inputData.aspectRatio : undefined;
32
+
33
+ const result = await persistence.saveAsProcessing(userId, {
34
+ scenarioId: scenario.id,
35
+ scenarioTitle: scenario.title || scenario.id,
36
+ prompt,
37
+ duration,
38
+ resolution,
39
+ creditCost,
40
+ aspectRatio,
41
+ provider: scenario.providerId ?? "fal",
42
+ outputType: scenario.outputType,
43
+ });
44
+ creationIdRef.current = result.creationId;
45
+
46
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
47
+ console.log("[PhotoBlockingGeneration] Saved as processing:", result.creationId);
48
+ }
49
+ } catch (err) {
50
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
51
+ console.error("[PhotoBlockingGeneration] saveAsProcessing error:", err);
52
+ }
53
+ }
54
+ }
@@ -12,6 +12,8 @@ import type { CreationPersistence } from "../../infrastructure/utils/creation-pe
12
12
  import type { WizardStrategy } from "../../infrastructure/strategies/wizard-strategy.types";
13
13
  import type { WizardScenarioData } from "./wizard-generation.types";
14
14
  import type { AlertMessages } from "../../../../../presentation/hooks/generation/types";
15
+ import { createSuccessHandler, createErrorHandler } from "./usePhotoBlockingGeneration.handlers";
16
+ import { saveCreationToProcessing } from "./usePhotoBlockingGeneration.saver";
15
17
 
16
18
 
17
19
  interface UsePhotoBlockingGenerationProps {
@@ -51,66 +53,25 @@ export function usePhotoBlockingGeneration(
51
53
  const creationIdRef = useRef<string | null>(null);
52
54
 
53
55
  const handleSuccess = useCallback(
54
- async (result: unknown) => {
55
- const typedResult = result as { imageUrl?: string; videoUrl?: string; audioUrl?: string; logSessionId?: string };
56
- const creationId = creationIdRef.current;
57
- const resultUri = typedResult.imageUrl || typedResult.videoUrl || typedResult.audioUrl;
58
-
59
- if (creationId && userId && resultUri) {
60
- try {
61
- await persistence.updateToCompleted(userId, creationId, {
62
- uri: resultUri,
63
- imageUrl: typedResult.imageUrl,
64
- videoUrl: typedResult.videoUrl,
65
- audioUrl: typedResult.audioUrl,
66
- logSessionId: typedResult.logSessionId,
67
- });
68
- } catch (err) {
69
- if (typeof __DEV__ !== "undefined" && __DEV__) {
70
- console.error("[PhotoBlockingGeneration] updateToCompleted error:", err);
71
- }
72
- }
73
- }
74
-
75
- creationIdRef.current = null;
76
-
77
- // Deduct credits after successful generation
78
- if (deductCredits && creditCost) {
79
- try {
80
- const deducted = await deductCredits(creditCost);
81
- if (!deducted) {
82
- onCreditsExhausted?.();
83
- }
84
- } catch (err) {
85
- if (typeof __DEV__ !== "undefined" && __DEV__) {
86
- console.error("[PhotoBlockingGeneration] deductCredits error:", err);
87
- }
88
- }
89
- }
90
-
91
- onSuccess?.(result);
92
- },
56
+ createSuccessHandler({
57
+ creationIdRef,
58
+ userId,
59
+ persistence,
60
+ deductCredits,
61
+ creditCost,
62
+ onSuccess,
63
+ onCreditsExhausted,
64
+ }),
93
65
  [userId, persistence, deductCredits, creditCost, onSuccess, onCreditsExhausted],
94
66
  );
95
67
 
96
68
  const handleError = useCallback(
97
- async (err: { message: string; originalError?: Error & { logSessionId?: string } }) => {
98
- const creationId = creationIdRef.current;
99
- const logSessionId = err.originalError?.logSessionId;
100
-
101
- if (creationId && userId) {
102
- try {
103
- await persistence.updateToFailed(userId, creationId, err.message, logSessionId);
104
- } catch (updateErr) {
105
- if (typeof __DEV__ !== "undefined" && __DEV__) {
106
- console.error("[PhotoBlockingGeneration] updateToFailed error:", updateErr);
107
- }
108
- }
109
- }
110
-
111
- creationIdRef.current = null;
112
- onError?.(err.message);
113
- },
69
+ createErrorHandler({
70
+ creationIdRef,
71
+ userId,
72
+ persistence,
73
+ onError,
74
+ }),
114
75
  [userId, persistence, onError],
115
76
  );
116
77
 
@@ -124,37 +85,11 @@ export function usePhotoBlockingGeneration(
124
85
  const startGeneration = useCallback(
125
86
  async (input: unknown, prompt: string) => {
126
87
  // Save to Firestore first
127
- if (userId && prompt) {
128
- try {
129
- // Extract generation parameters from input (for image generation, no duration/resolution)
130
- const inputData = input as Record<string, unknown>;
131
- const duration = typeof inputData?.duration === "number" ? inputData.duration : undefined;
132
- const resolution = typeof inputData?.resolution === "string" ? inputData.resolution : undefined;
133
-
134
- const aspectRatio = typeof inputData?.aspectRatio === "string" ? inputData.aspectRatio : undefined;
135
-
136
- const result = await persistence.saveAsProcessing(userId, {
137
- scenarioId: scenario.id,
138
- scenarioTitle: scenario.title || scenario.id,
139
- prompt,
140
- duration,
141
- resolution,
142
- creditCost,
143
- aspectRatio,
144
- provider: scenario.providerId ?? "fal",
145
- outputType: scenario.outputType,
146
- });
147
- creationIdRef.current = result.creationId;
148
-
149
- if (typeof __DEV__ !== "undefined" && __DEV__) {
150
- console.log("[PhotoBlockingGeneration] Saved as processing:", result.creationId);
151
- }
152
- } catch (err) {
153
- if (typeof __DEV__ !== "undefined" && __DEV__) {
154
- console.error("[PhotoBlockingGeneration] saveAsProcessing error:", err);
155
- }
156
- }
157
- }
88
+ await saveCreationToProcessing(
89
+ { userId, scenario, persistence, creditCost, creationIdRef },
90
+ input,
91
+ prompt,
92
+ );
158
93
 
159
94
  // Start blocking generation
160
95
  await generate(input);