@umituz/react-native-ai-generation-content 1.26.7 → 1.26.9

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 (29) hide show
  1. package/package.json +1 -1
  2. package/src/domains/generation/application/generation-strategy.factory.ts +1 -3
  3. package/src/domains/generation/infrastructure/executors/executor-factory.ts +1 -1
  4. package/src/domains/generation/infrastructure/flow/step-builder.ts +2 -11
  5. package/src/domains/generation/infrastructure/flow/useFlow.ts +1 -1
  6. package/src/domains/generation/infrastructure/flow/useFlowStore.ts +1 -1
  7. package/src/domains/generation/presentation/useAIGeneration.hook.ts +9 -3
  8. package/src/domains/generation/wizard/domain/entities/wizard-config.types.ts +1 -1
  9. package/src/domains/generation/wizard/index.ts +0 -29
  10. package/src/domains/generation/wizard/infrastructure/builders/dynamic-step-builder.ts +2 -3
  11. package/src/domains/generation/wizard/infrastructure/strategies/wizard-strategy.factory.ts +13 -15
  12. package/src/domains/generation/wizard/presentation/hooks/usePhotoUploadState.ts +2 -2
  13. package/src/domains/generation/wizard/presentation/hooks/useWizardGeneration.ts +2 -2
  14. package/src/domains/scenarios/configs/wizard-configs.ts +1 -1
  15. package/src/index.ts +1 -1
  16. package/src/infrastructure/wrappers/synchronous-generation.wrapper.ts +3 -2
  17. package/src/presentation/hooks/generation/index.ts +0 -1
  18. package/src/presentation/hooks/generation/orchestrator.ts +8 -3
  19. package/src/presentation/hooks/generation/useAIGenerateState.ts +3 -0
  20. package/src/presentation/hooks/index.ts +0 -1
  21. package/src/presentation/layouts/types/layout-props.ts +30 -4
  22. package/src/domains/generation/wizard/infrastructure/renderers/step-renderer.tsx +0 -107
  23. package/src/domains/generation/wizard/presentation/components/GenericWizardFlow.tsx +0 -297
  24. package/src/domains/generation/wizard/presentation/screens/GeneratingScreen.tsx +0 -123
  25. package/src/domains/generation/wizard/presentation/screens/GenericPhotoUploadScreen.tsx +0 -222
  26. package/src/domains/generation/wizard/presentation/steps/PhotoUploadStep.tsx +0 -66
  27. package/src/domains/generation/wizard/presentation/steps/SelectionStep.tsx +0 -244
  28. package/src/domains/generation/wizard/presentation/steps/TextInputStep.tsx +0 -199
  29. package/src/presentation/hooks/generation/useAIFeatureGeneration.ts +0 -180
@@ -1,297 +0,0 @@
1
- /**
2
- * Generic Wizard Flow Component
3
- * ONE wizard to rule them all!
4
- *
5
- * Works for:
6
- * - Couple features (romantic-kiss, ai-hug, etc.)
7
- * - Face swap
8
- * - Image-to-video
9
- * - Text-to-video
10
- * - ANY future feature!
11
- *
12
- * NO feature-specific code here - everything driven by configuration!
13
- */
14
-
15
- import React, { useMemo, useCallback, useEffect, useRef } from "react";
16
- import { View, StyleSheet } from "react-native";
17
- import { useAppDesignTokens } from "@umituz/react-native-design-system";
18
- import { useFlow } from "../../../../infrastructure/flow/useFlow";
19
- import { StepType } from "../../../../domain/entities/flow-config.types";
20
- import type { StepDefinition } from "../../../../domain/entities/flow-config.types";
21
- import { renderStep } from "../../infrastructure/renderers/step-renderer";
22
- import type { WizardFeatureConfig } from "../../domain/entities/wizard-config.types";
23
- import { buildFlowStepsFromWizard } from "../../infrastructure/builders/dynamic-step-builder";
24
- import { useWizardGeneration, type WizardScenarioData } from "../hooks/useWizardGeneration";
25
- import type { AlertMessages } from "../../../../presentation/hooks/generation/types";
26
-
27
- export interface GenericWizardFlowProps {
28
- readonly featureConfig: WizardFeatureConfig;
29
- readonly scenario?: WizardScenarioData;
30
- readonly userId?: string;
31
- readonly alertMessages?: AlertMessages;
32
- readonly onStepChange?: (stepId: string, stepType: StepType | string) => void;
33
- readonly onGenerationStart?: (data: Record<string, unknown>, proceedToGenerating: () => void) => void;
34
- readonly onGenerationComplete?: (result: unknown) => void;
35
- readonly onGenerationError?: (error: string) => void;
36
- readonly onCreditsExhausted?: () => void;
37
- readonly onBack?: () => void;
38
- readonly t: (key: string) => string;
39
- readonly translations?: Record<string, string>;
40
- readonly renderPreview?: (onContinue: () => void) => React.ReactElement | null;
41
- readonly renderGenerating?: (progress: number) => React.ReactElement | null;
42
- readonly renderResult?: (result: unknown) => React.ReactElement | null;
43
- }
44
-
45
- export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
46
- featureConfig,
47
- scenario,
48
- userId,
49
- alertMessages,
50
- onStepChange,
51
- onGenerationStart,
52
- onGenerationComplete,
53
- onGenerationError,
54
- onCreditsExhausted,
55
- onBack,
56
- t,
57
- translations,
58
- renderPreview,
59
- renderGenerating,
60
- renderResult,
61
- }) => {
62
- const tokens = useAppDesignTokens();
63
-
64
- // Build flow steps from wizard config
65
- const flowSteps = useMemo<StepDefinition[]>(() => {
66
- return buildFlowStepsFromWizard(featureConfig, {
67
- includePreview: !!renderPreview,
68
- includeGenerating: !!renderGenerating,
69
- });
70
- }, [featureConfig, renderPreview, renderGenerating]);
71
-
72
- // Initialize flow and destructure to prevent infinite loops
73
- const flow = useFlow({
74
- steps: flowSteps,
75
- initialStepIndex: 0,
76
- });
77
-
78
- // Destructure flow to get stable references for useCallback dependencies
79
- const {
80
- currentStep,
81
- currentStepIndex,
82
- customData,
83
- generationProgress,
84
- generationResult,
85
- nextStep,
86
- previousStep,
87
- setCustomData,
88
- updateProgress,
89
- } = flow;
90
-
91
- // Handle progress change - memoized to prevent infinite loops
92
- const handleProgressChange = useCallback(
93
- (progress: number) => {
94
- updateProgress(progress);
95
- },
96
- [updateProgress],
97
- );
98
-
99
- // Ensure scenario has required fields - use feature config as fallback
100
- const validatedScenario = useMemo(() => {
101
- if (typeof __DEV__ !== "undefined" && __DEV__) {
102
- console.log("[GenericWizardFlow] Validating scenario", {
103
- hasScenario: !!scenario,
104
- scenarioId: scenario?.id,
105
- hasAiPrompt: scenario?.aiPrompt !== undefined,
106
- hasModel: !!scenario?.model,
107
- scenarioModel: scenario?.model,
108
- outputType: scenario?.outputType,
109
- });
110
- }
111
-
112
- if (scenario && scenario.id && scenario.aiPrompt !== undefined) {
113
- if (typeof __DEV__ !== "undefined" && __DEV__) {
114
- console.log("[GenericWizardFlow] Scenario validation passed", {
115
- scenarioId: scenario.id,
116
- model: scenario.model,
117
- outputType: scenario.outputType,
118
- });
119
- }
120
- return scenario;
121
- }
122
-
123
- // Fallback to feature config
124
- if (typeof __DEV__ !== "undefined" && __DEV__) {
125
- console.warn("[GenericWizardFlow] Scenario missing required fields, using fallback", {
126
- hasScenario: !!scenario,
127
- scenarioId: scenario?.id,
128
- featureConfigId: featureConfig.id,
129
- });
130
- }
131
-
132
- return {
133
- id: featureConfig.id,
134
- aiPrompt: "",
135
- outputType: "image" as const, // Default to image for safety
136
- title: featureConfig.id,
137
- };
138
- }, [scenario, featureConfig.id]);
139
-
140
- // Generation hook - handles AI generation automatically
141
- const generationHook = useWizardGeneration({
142
- scenario: validatedScenario,
143
- wizardData: customData,
144
- userId,
145
- isGeneratingStep: currentStep?.type === StepType.GENERATING,
146
- alertMessages,
147
- onSuccess: onGenerationComplete,
148
- onError: onGenerationError,
149
- onProgressChange: handleProgressChange,
150
- onCreditsExhausted,
151
- });
152
-
153
- // Track previous step ID to prevent infinite loops
154
- const prevStepIdRef = useRef<string | undefined>(undefined);
155
-
156
- // DEBUG logging
157
- if (typeof __DEV__ !== "undefined" && __DEV__) {
158
- console.log("[GenericWizardFlow] Render", {
159
- featureId: featureConfig.id,
160
- currentStepId: currentStep?.id,
161
- currentStepType: currentStep?.type,
162
- stepIndex: currentStepIndex,
163
- totalSteps: flowSteps.length,
164
- });
165
- }
166
-
167
- // Notify parent when step changes
168
- // Only call onStepChange when step ID actually changes (not on every object reference change)
169
- useEffect(() => {
170
- if (currentStep && onStepChange) {
171
- const currentStepId = currentStep.id;
172
- // Only notify if step ID changed
173
- if (prevStepIdRef.current !== currentStepId) {
174
- prevStepIdRef.current = currentStepId;
175
- if (typeof __DEV__ !== "undefined" && __DEV__) {
176
- console.log("[GenericWizardFlow] Step changed", {
177
- stepId: currentStep.id,
178
- stepType: currentStep.type,
179
- });
180
- }
181
- onStepChange(currentStep.id, currentStep.type);
182
- }
183
- }
184
- }, [currentStep, currentStepIndex, onStepChange]);
185
-
186
- // Handle step continue
187
- const handleStepContinue = useCallback(
188
- (stepData: Record<string, unknown>) => {
189
- if (typeof __DEV__ !== "undefined" && __DEV__) {
190
- console.log("[GenericWizardFlow] Step continue", {
191
- stepId: currentStep?.id,
192
- data: stepData,
193
- });
194
- }
195
-
196
- // Store step data in custom data
197
- Object.entries(stepData).forEach(([key, value]) => {
198
- setCustomData(key, value);
199
- });
200
-
201
- // Check if this is the last step before generating
202
- if (currentStepIndex === flowSteps.length - 2) {
203
- // Next step is GENERATING
204
- // Notify parent and provide callback to proceed to generating
205
- // Parent will call proceedToGenerating() after feature gate passes
206
- if (onGenerationStart) {
207
- onGenerationStart(customData, () => {
208
- if (typeof __DEV__ !== "undefined" && __DEV__) {
209
- console.log("[GenericWizardFlow] Proceeding to GENERATING step");
210
- }
211
- nextStep();
212
- });
213
- }
214
- // DON'T call nextStep() here - parent will call it via proceedToGenerating callback
215
- return;
216
- }
217
-
218
- // Move to next step (for all non-generation steps)
219
- nextStep();
220
- },
221
- [currentStep, currentStepIndex, customData, setCustomData, nextStep, flowSteps.length, onGenerationStart],
222
- );
223
-
224
- // Handle back
225
- const handleBack = useCallback(() => {
226
- if (currentStepIndex === 0) {
227
- onBack?.();
228
- } else {
229
- previousStep();
230
- }
231
- }, [currentStepIndex, previousStep, onBack]);
232
-
233
- // Render current step
234
- const renderCurrentStep = useCallback(() => {
235
- const step = currentStep;
236
- if (!step) {
237
- if (typeof __DEV__ !== "undefined" && __DEV__) {
238
- console.warn("[GenericWizardFlow] No current step!");
239
- }
240
- return null;
241
- }
242
-
243
- if (typeof __DEV__ !== "undefined" && __DEV__) {
244
- console.log("[GenericWizardFlow] Rendering step", {
245
- stepId: step.id,
246
- stepType: step.type,
247
- });
248
- }
249
-
250
- // Special steps with custom renderers
251
- switch (step.type) {
252
- case StepType.SCENARIO_PREVIEW:
253
- // Preview continues to next step automatically
254
- return renderPreview?.(nextStep) || null;
255
-
256
- case StepType.GENERATING:
257
- return renderGenerating?.(generationProgress) || null;
258
-
259
- case StepType.RESULT_PREVIEW:
260
- return renderResult?.(generationResult) || null;
261
-
262
- default:
263
- // Use generic step renderer
264
- return renderStep({
265
- step,
266
- onContinue: handleStepContinue,
267
- onBack: handleBack,
268
- t,
269
- translations,
270
- });
271
- }
272
- }, [
273
- currentStep,
274
- generationProgress,
275
- generationResult,
276
- nextStep,
277
- renderPreview,
278
- renderGenerating,
279
- renderResult,
280
- handleStepContinue,
281
- handleBack,
282
- t,
283
- translations,
284
- ]);
285
-
286
- return (
287
- <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
288
- {renderCurrentStep()}
289
- </View>
290
- );
291
- };
292
-
293
- const styles = StyleSheet.create({
294
- container: {
295
- flex: 1,
296
- },
297
- });
@@ -1,123 +0,0 @@
1
- /**
2
- * Generic Generating Screen
3
- * Shows progress while AI generates content
4
- * Used by ALL features - NO feature-specific code!
5
- */
6
-
7
- import React from "react";
8
- import { View, StyleSheet, ActivityIndicator } from "react-native";
9
- import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
10
-
11
- export interface GeneratingScreenProps {
12
- readonly progress: number;
13
- readonly scenario?: {
14
- readonly id: string;
15
- readonly title?: string;
16
- };
17
- readonly t: (key: string) => string;
18
- readonly onCancel?: () => void;
19
- }
20
-
21
- export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
22
- progress,
23
- scenario,
24
- t,
25
- onCancel,
26
- }) => {
27
- const tokens = useAppDesignTokens();
28
-
29
- if (typeof __DEV__ !== "undefined" && __DEV__) {
30
- console.log("[GeneratingScreen] Rendering", {
31
- progress,
32
- scenarioId: scenario?.id,
33
- });
34
- }
35
-
36
- return (
37
- <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
38
- <View style={styles.content}>
39
- <ActivityIndicator size="large" color={tokens.colors.primary} />
40
-
41
- <AtomicText type="heading2" style={styles.title}>
42
- {t("generator.title")}
43
- </AtomicText>
44
-
45
- <AtomicText type="body" style={[styles.message, { color: tokens.colors.textSecondary }]}>
46
- {t("generator.waitMessage")}
47
- </AtomicText>
48
-
49
- {/* Progress Bar */}
50
- <View style={styles.progressContainer}>
51
- <View style={[styles.progressBar, { backgroundColor: tokens.colors.surfaceVariant }]}>
52
- <View
53
- style={[
54
- styles.progressFill,
55
- {
56
- backgroundColor: tokens.colors.primary,
57
- width: `${Math.min(100, Math.max(0, progress))}%`,
58
- },
59
- ]}
60
- />
61
- </View>
62
- <AtomicText type="caption" style={[styles.progressText, { color: tokens.colors.textSecondary }]}>
63
- {Math.round(progress)}%
64
- </AtomicText>
65
- </View>
66
-
67
- {/* Scenario Info */}
68
- {scenario && (
69
- <AtomicText type="caption" style={[styles.hint, { color: tokens.colors.textSecondary }]}>
70
- {scenario.title || scenario.id}
71
- </AtomicText>
72
- )}
73
-
74
- {/* Hint */}
75
- <AtomicText type="caption" style={[styles.hint, { color: tokens.colors.textSecondary }]}>
76
- {t("generator.hint")}
77
- </AtomicText>
78
- </View>
79
- </View>
80
- );
81
- };
82
-
83
- const styles = StyleSheet.create({
84
- container: {
85
- flex: 1,
86
- justifyContent: "center",
87
- alignItems: "center",
88
- },
89
- content: {
90
- width: "80%",
91
- maxWidth: 400,
92
- alignItems: "center",
93
- gap: 16,
94
- },
95
- title: {
96
- textAlign: "center",
97
- marginTop: 24,
98
- },
99
- message: {
100
- textAlign: "center",
101
- },
102
- progressContainer: {
103
- width: "100%",
104
- marginTop: 24,
105
- gap: 8,
106
- },
107
- progressBar: {
108
- height: 8,
109
- borderRadius: 4,
110
- overflow: "hidden",
111
- },
112
- progressFill: {
113
- height: "100%",
114
- borderRadius: 4,
115
- },
116
- progressText: {
117
- textAlign: "center",
118
- },
119
- hint: {
120
- textAlign: "center",
121
- marginTop: 8,
122
- },
123
- });
@@ -1,222 +0,0 @@
1
- /**
2
- * Generic Photo Upload Screen
3
- * Used by wizard domain for ANY photo upload step
4
- * NO feature-specific concepts (no partner, couple, etc.)
5
- * Works for: couple features, face-swap, image-to-video, ANY photo upload need
6
- */
7
-
8
- import React, { useMemo } from "react";
9
- import { View, TouchableOpacity, StyleSheet } from "react-native";
10
- import {
11
- useAppDesignTokens,
12
- ScreenLayout,
13
- AtomicText,
14
- AtomicIcon,
15
- NavigationHeader,
16
- type DesignTokens,
17
- } from "@umituz/react-native-design-system";
18
- import { PhotoUploadCard } from "../../../../presentation/components";
19
- import { FaceDetectionToggle } from "../../../../domains/face-detection";
20
- import { PhotoTips } from "../../../../features/partner-upload/presentation/components/PhotoTips";
21
- import type { UploadedImage } from "../../../../features/partner-upload/domain/types";
22
- import { usePhotoUploadState } from "../hooks/usePhotoUploadState";
23
-
24
- export interface PhotoUploadScreenTranslations {
25
- readonly title: string;
26
- readonly subtitle: string;
27
- readonly continue: string;
28
- readonly tapToUpload: string;
29
- readonly selectPhoto: string;
30
- readonly change: string;
31
- readonly analyzing: string;
32
- readonly fileTooLarge: string;
33
- readonly maxFileSize: string;
34
- readonly error: string;
35
- readonly uploadFailed: string;
36
- readonly aiDisclosure?: string;
37
- }
38
-
39
- export interface PhotoUploadScreenConfig {
40
- readonly showFaceDetection?: boolean;
41
- readonly showPhotoTips?: boolean;
42
- readonly maxFileSizeMB?: number;
43
- }
44
-
45
- export interface PhotoUploadScreenProps {
46
- readonly translations: PhotoUploadScreenTranslations;
47
- readonly t: (key: string) => string;
48
- readonly config?: PhotoUploadScreenConfig;
49
- readonly faceDetectionEnabled?: boolean;
50
- readonly onFaceDetectionToggle?: (enabled: boolean) => void;
51
- readonly onBack: () => void;
52
- readonly onContinue: (image: UploadedImage) => void;
53
- }
54
-
55
- const DEFAULT_CONFIG: PhotoUploadScreenConfig = {
56
- showFaceDetection: false,
57
- showPhotoTips: true,
58
- maxFileSizeMB: 10,
59
- };
60
-
61
- export const GenericPhotoUploadScreen: React.FC<PhotoUploadScreenProps> = ({
62
- translations,
63
- t,
64
- config = DEFAULT_CONFIG,
65
- faceDetectionEnabled = false,
66
- onFaceDetectionToggle,
67
- onBack,
68
- onContinue,
69
- }) => {
70
- const tokens = useAppDesignTokens();
71
-
72
- const { image, handlePickImage, canContinue } = usePhotoUploadState({
73
- config: { maxFileSizeMB: config.maxFileSizeMB },
74
- translations: {
75
- fileTooLarge: translations.fileTooLarge,
76
- maxFileSize: translations.maxFileSize,
77
- error: translations.error,
78
- uploadFailed: translations.uploadFailed,
79
- },
80
- });
81
-
82
- const handleContinuePress = () => {
83
- if (!canContinue || !image) return;
84
- onContinue(image);
85
- };
86
-
87
- const styles = useMemo(() => createStyles(tokens), [tokens]);
88
- const showFaceDetection = config.showFaceDetection ?? false;
89
- const showPhotoTips = config.showPhotoTips ?? true;
90
-
91
- return (
92
- <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
93
- <NavigationHeader
94
- title={translations.title}
95
- onBackPress={onBack}
96
- rightElement={
97
- <TouchableOpacity
98
- onPress={handleContinuePress}
99
- activeOpacity={0.7}
100
- disabled={!canContinue || !image}
101
- style={[
102
- styles.continueButton,
103
- {
104
- backgroundColor: canContinue && image ? tokens.colors.primary : tokens.colors.surfaceVariant,
105
- opacity: canContinue && image ? 1 : 0.5,
106
- },
107
- ]}
108
- >
109
- <AtomicText
110
- type="bodyMedium"
111
- style={[
112
- styles.continueText,
113
- { color: canContinue && image ? tokens.colors.onPrimary : tokens.colors.textSecondary },
114
- ]}
115
- >
116
- {translations.continue}
117
- </AtomicText>
118
- <AtomicIcon
119
- name="arrow-forward"
120
- size="sm"
121
- color={canContinue && image ? "onPrimary" : "textSecondary"}
122
- />
123
- </TouchableOpacity>
124
- }
125
- />
126
- <ScreenLayout
127
- edges={["left", "right"]}
128
- backgroundColor="transparent"
129
- scrollable={true}
130
- keyboardAvoiding={true}
131
- contentContainerStyle={styles.scrollContent}
132
- hideScrollIndicator={true}
133
- >
134
- <AtomicText style={[styles.subtitle, { color: tokens.colors.textSecondary }]}>
135
- {translations.subtitle}
136
- </AtomicText>
137
-
138
- {/* Photo Tips - InfoGrid version */}
139
- {showPhotoTips && (
140
- <PhotoTips
141
- t={t}
142
- titleKey="photoUpload.tips.title"
143
- headerIcon="bulb"
144
- style={{ marginHorizontal: 24, marginBottom: 20 }}
145
- />
146
- )}
147
-
148
- {showFaceDetection && onFaceDetectionToggle && (
149
- <FaceDetectionToggle
150
- isEnabled={faceDetectionEnabled}
151
- onToggle={onFaceDetectionToggle}
152
- label={t("photoUpload.faceDetection")}
153
- hidden={true}
154
- />
155
- )}
156
-
157
- <PhotoUploadCard
158
- imageUri={image?.previewUrl || null}
159
- onPress={handlePickImage}
160
- isValidating={false}
161
- isValid={null}
162
- translations={{
163
- tapToUpload: translations.tapToUpload,
164
- selectPhoto: translations.selectPhoto,
165
- change: translations.change,
166
- analyzing: translations.analyzing,
167
- }}
168
- />
169
-
170
- {translations.aiDisclosure && (
171
- <View style={styles.disclosureContainer}>
172
- <AtomicText
173
- type="labelSmall"
174
- style={[styles.disclosureText, { color: tokens.colors.textSecondary }]}
175
- >
176
- {translations.aiDisclosure}
177
- </AtomicText>
178
- </View>
179
- )}
180
- </ScreenLayout>
181
- </View>
182
- );
183
- };
184
-
185
- const createStyles = (tokens: DesignTokens) =>
186
- StyleSheet.create({
187
- container: {
188
- flex: 1,
189
- },
190
- scrollContent: {
191
- paddingBottom: 40,
192
- },
193
- subtitle: {
194
- fontSize: 16,
195
- textAlign: "center",
196
- marginHorizontal: 24,
197
- marginBottom: 24,
198
- },
199
- continueButton: {
200
- flexDirection: "row",
201
- alignItems: "center",
202
- paddingHorizontal: tokens.spacing.md,
203
- paddingVertical: tokens.spacing.xs,
204
- borderRadius: tokens.borders.radius.full,
205
- },
206
- continueText: {
207
- fontWeight: "800",
208
- marginRight: 4,
209
- },
210
- disclosureContainer: {
211
- marginTop: 24,
212
- marginHorizontal: 24,
213
- padding: 16,
214
- borderRadius: 12,
215
- backgroundColor: tokens.colors.surfaceVariant + "40",
216
- },
217
- disclosureText: {
218
- textAlign: "center",
219
- lineHeight: 18,
220
- opacity: 0.8,
221
- },
222
- });
@@ -1,66 +0,0 @@
1
- /**
2
- * Generic Photo Upload Step
3
- * Used by ALL features that need photo uploads
4
- * (couple, face-swap, image-to-video, etc.)
5
- */
6
-
7
- import React from "react";
8
- import type { PhotoUploadStepConfig } from "../../domain/entities/wizard-config.types";
9
-
10
- // Use wizard domain's generic photo upload screen - NO feature-specific references!
11
- import { GenericPhotoUploadScreen } from "../screens/GenericPhotoUploadScreen";
12
- import type { UploadedImage } from "../../../../features/partner-upload/domain/types";
13
-
14
- export interface PhotoUploadStepProps {
15
- readonly config: PhotoUploadStepConfig;
16
- readonly onContinue: (image: UploadedImage) => void;
17
- readonly onBack: () => void;
18
- readonly t: (key: string) => string;
19
- readonly translations?: Record<string, string>;
20
- }
21
-
22
- export const PhotoUploadStep: React.FC<PhotoUploadStepProps> = ({
23
- config,
24
- onContinue,
25
- onBack,
26
- t,
27
- translations,
28
- }) => {
29
- if (typeof __DEV__ !== "undefined" && __DEV__) {
30
- console.log("[PhotoUploadStep] Rendering", {
31
- stepId: config.id,
32
- label: config.label,
33
- });
34
- }
35
-
36
- return (
37
- <GenericPhotoUploadScreen
38
- translations={{
39
- title: config.titleKey ? t(config.titleKey) : config.label || "Upload Photo",
40
- subtitle: config.subtitleKey ? t(config.subtitleKey) : t("photoUpload.subtitle"),
41
- continue: t("common.continue"),
42
- tapToUpload: t("photoUpload.tapToUpload"),
43
- selectPhoto: t("photoUpload.selectPhoto"),
44
- change: t("common.change"),
45
- analyzing: t("photoUpload.analyzing"),
46
- fileTooLarge: t("common.errors.file_too_large"),
47
- maxFileSize: t("common.errors.max_file_size"),
48
- error: t("common.error"),
49
- uploadFailed: t("common.errors.upload_failed"),
50
- }}
51
- t={t}
52
- config={{
53
- showFaceDetection: config.showFaceDetection ?? false,
54
- showPhotoTips: config.showPhotoTips ?? true,
55
- maxFileSizeMB: config.maxFileSizeMB ?? 10,
56
- }}
57
- onBack={onBack}
58
- onContinue={(image) => {
59
- if (typeof __DEV__ !== "undefined" && __DEV__) {
60
- console.log("[PhotoUploadStep] Photo uploaded", { stepId: config.id });
61
- }
62
- onContinue(image);
63
- }}
64
- />
65
- );
66
- };