@umituz/react-native-ai-generation-content 1.14.0 → 1.15.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 +2 -2
- package/src/index.ts +24 -0
- package/src/presentation/components/index.ts +1 -0
- package/src/presentation/components/photo-step/PhotoStep.tsx +96 -0
- package/src/presentation/components/photo-step/index.ts +2 -0
- package/src/presentation/hooks/index.ts +6 -0
- package/src/presentation/hooks/useGenerationFlow.ts +315 -0
- package/src/presentation/types/flow-config.types.ts +246 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Provider-agnostic AI generation orchestration for React Native",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
68
68
|
"@typescript-eslint/parser": "^7.0.0",
|
|
69
69
|
"@umituz/react-native-animation": "*",
|
|
70
|
-
"@umituz/react-native-design-system": "^2.
|
|
70
|
+
"@umituz/react-native-design-system": "^2.4.1",
|
|
71
71
|
"@umituz/react-native-firebase": "^1.13.20",
|
|
72
72
|
"@umituz/react-native-haptics": "^1.0.2",
|
|
73
73
|
"@umituz/react-native-image": "*",
|
package/src/index.ts
CHANGED
|
@@ -186,6 +186,7 @@ export {
|
|
|
186
186
|
usePendingJobs,
|
|
187
187
|
useBackgroundGeneration,
|
|
188
188
|
usePhotoGeneration,
|
|
189
|
+
useGenerationFlow,
|
|
189
190
|
} from "./presentation/hooks";
|
|
190
191
|
|
|
191
192
|
export type {
|
|
@@ -203,6 +204,8 @@ export type {
|
|
|
203
204
|
PhotoGenerationConfig,
|
|
204
205
|
PhotoGenerationState,
|
|
205
206
|
PhotoGenerationStatus,
|
|
207
|
+
UseGenerationFlowOptions,
|
|
208
|
+
UseGenerationFlowReturn,
|
|
206
209
|
} from "./presentation/hooks";
|
|
207
210
|
|
|
208
211
|
// =============================================================================
|
|
@@ -222,6 +225,7 @@ export {
|
|
|
222
225
|
ResultStoryCard,
|
|
223
226
|
ResultActions,
|
|
224
227
|
DEFAULT_RESULT_CONFIG,
|
|
228
|
+
PhotoStep,
|
|
225
229
|
} from "./presentation/components";
|
|
226
230
|
|
|
227
231
|
export type {
|
|
@@ -246,8 +250,28 @@ export type {
|
|
|
246
250
|
ResultActionsConfig,
|
|
247
251
|
ResultLayoutConfig,
|
|
248
252
|
ResultActionButton,
|
|
253
|
+
PhotoStepProps,
|
|
249
254
|
} from "./presentation/components";
|
|
250
255
|
|
|
256
|
+
// =============================================================================
|
|
257
|
+
// PRESENTATION LAYER - Flow Configuration
|
|
258
|
+
// =============================================================================
|
|
259
|
+
|
|
260
|
+
export {
|
|
261
|
+
DEFAULT_SINGLE_PHOTO_FLOW,
|
|
262
|
+
DEFAULT_DUAL_PHOTO_FLOW,
|
|
263
|
+
} from "./presentation/types/flow-config.types";
|
|
264
|
+
|
|
265
|
+
export type {
|
|
266
|
+
PhotoStepConfig,
|
|
267
|
+
TextInputStepConfig,
|
|
268
|
+
PreviewStepConfig,
|
|
269
|
+
GenerationFlowConfig,
|
|
270
|
+
PhotoStepData,
|
|
271
|
+
TextInputStepData,
|
|
272
|
+
GenerationFlowState,
|
|
273
|
+
} from "./presentation/types/flow-config.types";
|
|
274
|
+
|
|
251
275
|
// =============================================================================
|
|
252
276
|
// DOMAINS - AI Prompts
|
|
253
277
|
// =============================================================================
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhotoStep Component
|
|
3
|
+
* Configurable photo upload step using design system components
|
|
4
|
+
*
|
|
5
|
+
* @package @umituz/react-native-ai-generation-content
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, { useMemo } from "react";
|
|
9
|
+
import { View, StyleSheet, type ViewStyle, type StyleProp } from "react-native";
|
|
10
|
+
import {
|
|
11
|
+
StepHeader,
|
|
12
|
+
PhotoUploadCard,
|
|
13
|
+
} from "@umituz/react-native-design-system";
|
|
14
|
+
import type { PhotoStepConfig } from "../../types/flow-config.types";
|
|
15
|
+
|
|
16
|
+
export interface PhotoStepProps {
|
|
17
|
+
/** Step configuration */
|
|
18
|
+
config: PhotoStepConfig;
|
|
19
|
+
/** Current photo URI */
|
|
20
|
+
imageUri: string | null;
|
|
21
|
+
/** Photo preview URL */
|
|
22
|
+
previewUrl?: string;
|
|
23
|
+
/** Whether photo is being validated */
|
|
24
|
+
isValidating?: boolean;
|
|
25
|
+
/** Whether photo is valid */
|
|
26
|
+
isValid?: boolean | null;
|
|
27
|
+
/** Handler for photo selection */
|
|
28
|
+
onPhotoSelect: () => void;
|
|
29
|
+
/** Whether photo selection is disabled */
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
/** Step title */
|
|
32
|
+
title: string;
|
|
33
|
+
/** Step subtitle */
|
|
34
|
+
subtitle?: string;
|
|
35
|
+
/** Translation strings for photo upload card */
|
|
36
|
+
translations: {
|
|
37
|
+
tapToUpload: string;
|
|
38
|
+
selectPhoto: string;
|
|
39
|
+
change: string;
|
|
40
|
+
analyzing?: string;
|
|
41
|
+
};
|
|
42
|
+
/** Additional content to render below photo card */
|
|
43
|
+
children?: React.ReactNode;
|
|
44
|
+
/** Container style */
|
|
45
|
+
style?: StyleProp<ViewStyle>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const PhotoStep: React.FC<PhotoStepProps> = ({
|
|
49
|
+
config,
|
|
50
|
+
imageUri,
|
|
51
|
+
previewUrl,
|
|
52
|
+
isValidating = false,
|
|
53
|
+
isValid = null,
|
|
54
|
+
onPhotoSelect,
|
|
55
|
+
disabled = false,
|
|
56
|
+
title,
|
|
57
|
+
subtitle,
|
|
58
|
+
translations,
|
|
59
|
+
children,
|
|
60
|
+
style,
|
|
61
|
+
}) => {
|
|
62
|
+
const styles = useMemo(
|
|
63
|
+
() =>
|
|
64
|
+
StyleSheet.create({
|
|
65
|
+
container: {
|
|
66
|
+
flex: 1,
|
|
67
|
+
},
|
|
68
|
+
}),
|
|
69
|
+
[],
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<View style={[styles.container, style]}>
|
|
74
|
+
{/* Step Header */}
|
|
75
|
+
<StepHeader
|
|
76
|
+
title={title}
|
|
77
|
+
subtitle={subtitle}
|
|
78
|
+
config={config.header}
|
|
79
|
+
/>
|
|
80
|
+
|
|
81
|
+
{/* Photo Upload Card */}
|
|
82
|
+
<PhotoUploadCard
|
|
83
|
+
imageUri={previewUrl || imageUri}
|
|
84
|
+
onPress={onPhotoSelect}
|
|
85
|
+
isValidating={isValidating}
|
|
86
|
+
isValid={config.enableValidation ? isValid : null}
|
|
87
|
+
disabled={disabled}
|
|
88
|
+
config={config.photoCard}
|
|
89
|
+
translations={translations}
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
{/* Additional content (e.g., name input, tips, etc.) */}
|
|
93
|
+
{children}
|
|
94
|
+
</View>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
@@ -34,3 +34,9 @@ export type {
|
|
|
34
34
|
PhotoGenerationState,
|
|
35
35
|
PhotoGenerationStatus,
|
|
36
36
|
} from "./photo-generation.types";
|
|
37
|
+
|
|
38
|
+
export { useGenerationFlow } from "./useGenerationFlow";
|
|
39
|
+
export type {
|
|
40
|
+
UseGenerationFlowOptions,
|
|
41
|
+
UseGenerationFlowReturn,
|
|
42
|
+
} from "./useGenerationFlow";
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useGenerationFlow Hook
|
|
3
|
+
* Manages step-by-step generation flow state and navigation
|
|
4
|
+
*
|
|
5
|
+
* @package @umituz/react-native-ai-generation-content
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useState, useCallback, useMemo } from "react";
|
|
9
|
+
import type {
|
|
10
|
+
GenerationFlowConfig,
|
|
11
|
+
GenerationFlowState,
|
|
12
|
+
PhotoStepData,
|
|
13
|
+
PhotoStepConfig,
|
|
14
|
+
} from "../types/flow-config.types";
|
|
15
|
+
|
|
16
|
+
export interface UseGenerationFlowOptions {
|
|
17
|
+
/** Flow configuration */
|
|
18
|
+
config: GenerationFlowConfig;
|
|
19
|
+
/** Callback when flow is complete */
|
|
20
|
+
onComplete?: (state: GenerationFlowState) => void;
|
|
21
|
+
/** Callback when step changes */
|
|
22
|
+
onStepChange?: (stepIndex: number, stepConfig: PhotoStepConfig) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface UseGenerationFlowReturn {
|
|
26
|
+
/** Current flow state */
|
|
27
|
+
state: GenerationFlowState;
|
|
28
|
+
/** Current step configuration */
|
|
29
|
+
currentStepConfig: PhotoStepConfig | null;
|
|
30
|
+
/** Current step data */
|
|
31
|
+
currentStepData: PhotoStepData | null;
|
|
32
|
+
/** Whether can go to next step */
|
|
33
|
+
canGoNext: boolean;
|
|
34
|
+
/** Whether can go to previous step */
|
|
35
|
+
canGoBack: boolean;
|
|
36
|
+
/** Go to next step */
|
|
37
|
+
goNext: () => void;
|
|
38
|
+
/** Go to previous step */
|
|
39
|
+
goBack: () => void;
|
|
40
|
+
/** Update current step photo */
|
|
41
|
+
updatePhoto: (imageUri: string, previewUrl?: string) => void;
|
|
42
|
+
/** Update current step name */
|
|
43
|
+
updateName: (name: string) => void;
|
|
44
|
+
/** Update current step validation */
|
|
45
|
+
updateValidation: (isValid: boolean) => void;
|
|
46
|
+
/** Update text input */
|
|
47
|
+
updateTextInput: (text: string) => void;
|
|
48
|
+
/** Reset flow */
|
|
49
|
+
reset: () => void;
|
|
50
|
+
/** Complete flow */
|
|
51
|
+
complete: () => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Hook to manage generation flow state
|
|
56
|
+
*/
|
|
57
|
+
export const useGenerationFlow = ({
|
|
58
|
+
config,
|
|
59
|
+
onComplete,
|
|
60
|
+
onStepChange,
|
|
61
|
+
}: UseGenerationFlowOptions): UseGenerationFlowReturn => {
|
|
62
|
+
// Initialize state
|
|
63
|
+
const [state, setState] = useState<GenerationFlowState>(() => ({
|
|
64
|
+
currentStepIndex: 0,
|
|
65
|
+
photoSteps: config.photoSteps.map((step) => ({
|
|
66
|
+
id: step.id,
|
|
67
|
+
imageUri: null,
|
|
68
|
+
previewUrl: undefined,
|
|
69
|
+
name: undefined,
|
|
70
|
+
isValid: undefined,
|
|
71
|
+
validationStatus: "pending",
|
|
72
|
+
})),
|
|
73
|
+
textInput: config.textInputStep
|
|
74
|
+
? {
|
|
75
|
+
id: config.textInputStep.id,
|
|
76
|
+
text: "",
|
|
77
|
+
isValid: false,
|
|
78
|
+
}
|
|
79
|
+
: undefined,
|
|
80
|
+
isComplete: false,
|
|
81
|
+
isProcessing: false,
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
// Get current step configuration
|
|
85
|
+
const currentStepConfig = useMemo(() => {
|
|
86
|
+
if (state.currentStepIndex >= config.photoSteps.length) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return config.photoSteps[state.currentStepIndex];
|
|
90
|
+
}, [state.currentStepIndex, config.photoSteps]);
|
|
91
|
+
|
|
92
|
+
// Get current step data
|
|
93
|
+
const currentStepData = useMemo(() => {
|
|
94
|
+
if (state.currentStepIndex >= state.photoSteps.length) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
return state.photoSteps[state.currentStepIndex];
|
|
98
|
+
}, [state.currentStepIndex, state.photoSteps]);
|
|
99
|
+
|
|
100
|
+
// Check if current step is valid
|
|
101
|
+
const isCurrentStepValid = useMemo(() => {
|
|
102
|
+
if (!currentStepData || !currentStepConfig) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Check photo
|
|
107
|
+
if (!currentStepData.imageUri) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Check name if required
|
|
112
|
+
if (currentStepConfig.requireNameInput && !currentStepData.name) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Check validation if enabled
|
|
117
|
+
if (currentStepConfig.enableValidation && !currentStepData.isValid) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
}, [currentStepData, currentStepConfig]);
|
|
123
|
+
|
|
124
|
+
// Can go to next step
|
|
125
|
+
const canGoNext = useMemo(() => {
|
|
126
|
+
return isCurrentStepValid && !state.isProcessing;
|
|
127
|
+
}, [isCurrentStepValid, state.isProcessing]);
|
|
128
|
+
|
|
129
|
+
// Can go back
|
|
130
|
+
const canGoBack = useMemo(() => {
|
|
131
|
+
return (
|
|
132
|
+
state.currentStepIndex > 0 &&
|
|
133
|
+
config.behavior?.allowBack !== false &&
|
|
134
|
+
!state.isProcessing
|
|
135
|
+
);
|
|
136
|
+
}, [state.currentStepIndex, config.behavior?.allowBack, state.isProcessing]);
|
|
137
|
+
|
|
138
|
+
// Go to next step
|
|
139
|
+
const goNext = useCallback(() => {
|
|
140
|
+
if (!canGoNext) return;
|
|
141
|
+
|
|
142
|
+
setState((prev) => {
|
|
143
|
+
const nextIndex = prev.currentStepIndex + 1;
|
|
144
|
+
|
|
145
|
+
// If we've completed all photo steps, mark as complete
|
|
146
|
+
if (nextIndex >= config.photoSteps.length) {
|
|
147
|
+
const newState = {
|
|
148
|
+
...prev,
|
|
149
|
+
isComplete: true,
|
|
150
|
+
};
|
|
151
|
+
onComplete?.(newState);
|
|
152
|
+
return newState;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Move to next step
|
|
156
|
+
const newState = {
|
|
157
|
+
...prev,
|
|
158
|
+
currentStepIndex: nextIndex,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Notify step change
|
|
162
|
+
onStepChange?.(nextIndex, config.photoSteps[nextIndex]);
|
|
163
|
+
|
|
164
|
+
return newState;
|
|
165
|
+
});
|
|
166
|
+
}, [canGoNext, config.photoSteps, onComplete, onStepChange]);
|
|
167
|
+
|
|
168
|
+
// Go to previous step
|
|
169
|
+
const goBack = useCallback(() => {
|
|
170
|
+
if (!canGoBack) return;
|
|
171
|
+
|
|
172
|
+
setState((prev) => {
|
|
173
|
+
const prevIndex = prev.currentStepIndex - 1;
|
|
174
|
+
const newState = {
|
|
175
|
+
...prev,
|
|
176
|
+
currentStepIndex: prevIndex,
|
|
177
|
+
isComplete: false,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Notify step change
|
|
181
|
+
onStepChange?.(prevIndex, config.photoSteps[prevIndex]);
|
|
182
|
+
|
|
183
|
+
return newState;
|
|
184
|
+
});
|
|
185
|
+
}, [canGoBack, config.photoSteps, onStepChange]);
|
|
186
|
+
|
|
187
|
+
// Update photo
|
|
188
|
+
const updatePhoto = useCallback(
|
|
189
|
+
(imageUri: string, previewUrl?: string) => {
|
|
190
|
+
setState((prev) => {
|
|
191
|
+
const newPhotoSteps = [...prev.photoSteps];
|
|
192
|
+
newPhotoSteps[prev.currentStepIndex] = {
|
|
193
|
+
...newPhotoSteps[prev.currentStepIndex],
|
|
194
|
+
imageUri,
|
|
195
|
+
previewUrl,
|
|
196
|
+
validationStatus: "pending",
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
...prev,
|
|
201
|
+
photoSteps: newPhotoSteps,
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
[],
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
// Update name
|
|
209
|
+
const updateName = useCallback((name: string) => {
|
|
210
|
+
setState((prev) => {
|
|
211
|
+
const newPhotoSteps = [...prev.photoSteps];
|
|
212
|
+
newPhotoSteps[prev.currentStepIndex] = {
|
|
213
|
+
...newPhotoSteps[prev.currentStepIndex],
|
|
214
|
+
name,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
...prev,
|
|
219
|
+
photoSteps: newPhotoSteps,
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
}, []);
|
|
223
|
+
|
|
224
|
+
// Update validation
|
|
225
|
+
const updateValidation = useCallback((isValid: boolean) => {
|
|
226
|
+
setState((prev) => {
|
|
227
|
+
const newPhotoSteps = [...prev.photoSteps];
|
|
228
|
+
newPhotoSteps[prev.currentStepIndex] = {
|
|
229
|
+
...newPhotoSteps[prev.currentStepIndex],
|
|
230
|
+
isValid,
|
|
231
|
+
validationStatus: isValid ? "valid" : "invalid",
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
...prev,
|
|
236
|
+
photoSteps: newPhotoSteps,
|
|
237
|
+
};
|
|
238
|
+
});
|
|
239
|
+
}, []);
|
|
240
|
+
|
|
241
|
+
// Update text input
|
|
242
|
+
const updateTextInput = useCallback(
|
|
243
|
+
(text: string) => {
|
|
244
|
+
setState((prev) => {
|
|
245
|
+
if (!prev.textInput) return prev;
|
|
246
|
+
|
|
247
|
+
const minLength = config.textInputStep?.minLength ?? 0;
|
|
248
|
+
const maxLength = config.textInputStep?.maxLength ?? Infinity;
|
|
249
|
+
const isValid = text.length >= minLength && text.length <= maxLength;
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
...prev,
|
|
253
|
+
textInput: {
|
|
254
|
+
...prev.textInput,
|
|
255
|
+
text,
|
|
256
|
+
isValid,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
});
|
|
260
|
+
},
|
|
261
|
+
[config.textInputStep],
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
// Reset flow
|
|
265
|
+
const reset = useCallback(() => {
|
|
266
|
+
setState({
|
|
267
|
+
currentStepIndex: 0,
|
|
268
|
+
photoSteps: config.photoSteps.map((step) => ({
|
|
269
|
+
id: step.id,
|
|
270
|
+
imageUri: null,
|
|
271
|
+
previewUrl: undefined,
|
|
272
|
+
name: undefined,
|
|
273
|
+
isValid: undefined,
|
|
274
|
+
validationStatus: "pending",
|
|
275
|
+
})),
|
|
276
|
+
textInput: config.textInputStep
|
|
277
|
+
? {
|
|
278
|
+
id: config.textInputStep.id,
|
|
279
|
+
text: "",
|
|
280
|
+
isValid: false,
|
|
281
|
+
}
|
|
282
|
+
: undefined,
|
|
283
|
+
isComplete: false,
|
|
284
|
+
isProcessing: false,
|
|
285
|
+
});
|
|
286
|
+
}, [config.photoSteps, config.textInputStep]);
|
|
287
|
+
|
|
288
|
+
// Complete flow
|
|
289
|
+
const complete = useCallback(() => {
|
|
290
|
+
setState((prev) => {
|
|
291
|
+
const newState = {
|
|
292
|
+
...prev,
|
|
293
|
+
isComplete: true,
|
|
294
|
+
};
|
|
295
|
+
onComplete?.(newState);
|
|
296
|
+
return newState;
|
|
297
|
+
});
|
|
298
|
+
}, [onComplete]);
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
state,
|
|
302
|
+
currentStepConfig,
|
|
303
|
+
currentStepData,
|
|
304
|
+
canGoNext,
|
|
305
|
+
canGoBack,
|
|
306
|
+
goNext,
|
|
307
|
+
goBack,
|
|
308
|
+
updatePhoto,
|
|
309
|
+
updateName,
|
|
310
|
+
updateValidation,
|
|
311
|
+
updateTextInput,
|
|
312
|
+
reset,
|
|
313
|
+
complete,
|
|
314
|
+
};
|
|
315
|
+
};
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow Configuration Types
|
|
3
|
+
* Configuration system for step-by-step generation flows
|
|
4
|
+
*
|
|
5
|
+
* @package @umituz/react-native-ai-generation-content
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { StepHeaderConfig } from "@umituz/react-native-design-system";
|
|
9
|
+
import type { PhotoUploadCardConfig } from "@umituz/react-native-design-system";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Photo upload step configuration
|
|
13
|
+
*/
|
|
14
|
+
export interface PhotoStepConfig {
|
|
15
|
+
/** Whether this step is enabled */
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
/** Step order (1, 2, 3, etc.) */
|
|
18
|
+
order: number;
|
|
19
|
+
/** Step identifier */
|
|
20
|
+
id: string;
|
|
21
|
+
/** Header configuration */
|
|
22
|
+
header?: StepHeaderConfig;
|
|
23
|
+
/** Photo upload card configuration */
|
|
24
|
+
photoCard?: PhotoUploadCardConfig;
|
|
25
|
+
/** Whether name input is required */
|
|
26
|
+
requireNameInput?: boolean;
|
|
27
|
+
/** Whether photo validation is enabled */
|
|
28
|
+
enableValidation?: boolean;
|
|
29
|
+
/** Validation type */
|
|
30
|
+
validationType?: "none" | "face-detection" | "custom";
|
|
31
|
+
/** Whether to show photo tips */
|
|
32
|
+
showPhotoTips?: boolean;
|
|
33
|
+
/** Custom validation function */
|
|
34
|
+
customValidator?: (imageUri: string) => Promise<boolean>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Text input step configuration
|
|
39
|
+
*/
|
|
40
|
+
export interface TextInputStepConfig {
|
|
41
|
+
/** Whether this step is enabled */
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
/** Step order */
|
|
44
|
+
order: number;
|
|
45
|
+
/** Step identifier */
|
|
46
|
+
id: string;
|
|
47
|
+
/** Header configuration */
|
|
48
|
+
header?: StepHeaderConfig;
|
|
49
|
+
/** Minimum character length */
|
|
50
|
+
minLength?: number;
|
|
51
|
+
/** Maximum character length */
|
|
52
|
+
maxLength?: number;
|
|
53
|
+
/** Placeholder text */
|
|
54
|
+
placeholder?: string;
|
|
55
|
+
/** Whether to show character counter */
|
|
56
|
+
showCharacterCount?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Preview step configuration
|
|
61
|
+
*/
|
|
62
|
+
export interface PreviewStepConfig {
|
|
63
|
+
/** Whether this step is enabled */
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
/** Step order */
|
|
66
|
+
order: number;
|
|
67
|
+
/** Step identifier */
|
|
68
|
+
id: string;
|
|
69
|
+
/** Header configuration */
|
|
70
|
+
header?: StepHeaderConfig;
|
|
71
|
+
/** Whether to show edit buttons */
|
|
72
|
+
allowEditing?: boolean;
|
|
73
|
+
/** Preview layout style */
|
|
74
|
+
layout?: "grid" | "list" | "carousel";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Complete flow configuration
|
|
79
|
+
*/
|
|
80
|
+
export interface GenerationFlowConfig {
|
|
81
|
+
/** Photo upload steps (can be 1 or multiple) */
|
|
82
|
+
photoSteps: PhotoStepConfig[];
|
|
83
|
+
/** Text input step */
|
|
84
|
+
textInputStep?: TextInputStepConfig;
|
|
85
|
+
/** Preview step */
|
|
86
|
+
previewStep?: PreviewStepConfig;
|
|
87
|
+
/** Flow behavior */
|
|
88
|
+
behavior?: {
|
|
89
|
+
/** Whether to allow going back */
|
|
90
|
+
allowBack?: boolean;
|
|
91
|
+
/** Whether to show progress indicator */
|
|
92
|
+
showProgress?: boolean;
|
|
93
|
+
/** Whether to auto-advance after photo selection */
|
|
94
|
+
autoAdvance?: boolean;
|
|
95
|
+
/** Whether to require authentication */
|
|
96
|
+
requireAuth?: boolean;
|
|
97
|
+
/** Whether to check feature gate */
|
|
98
|
+
checkFeatureGate?: boolean;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Default single photo flow configuration
|
|
104
|
+
*/
|
|
105
|
+
export const DEFAULT_SINGLE_PHOTO_FLOW: GenerationFlowConfig = {
|
|
106
|
+
photoSteps: [
|
|
107
|
+
{
|
|
108
|
+
enabled: true,
|
|
109
|
+
order: 1,
|
|
110
|
+
id: "photo-1",
|
|
111
|
+
header: {
|
|
112
|
+
showStepIndicator: false,
|
|
113
|
+
titleAlignment: "center",
|
|
114
|
+
titleFontSize: 28,
|
|
115
|
+
subtitleFontSize: 16,
|
|
116
|
+
},
|
|
117
|
+
photoCard: {
|
|
118
|
+
aspectRatio: 1,
|
|
119
|
+
borderRadius: 28,
|
|
120
|
+
showValidationStatus: true,
|
|
121
|
+
allowChange: true,
|
|
122
|
+
borderStyle: "dashed",
|
|
123
|
+
},
|
|
124
|
+
requireNameInput: true,
|
|
125
|
+
enableValidation: false,
|
|
126
|
+
validationType: "none",
|
|
127
|
+
showPhotoTips: true,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
behavior: {
|
|
131
|
+
allowBack: false,
|
|
132
|
+
showProgress: false,
|
|
133
|
+
autoAdvance: false,
|
|
134
|
+
requireAuth: false,
|
|
135
|
+
checkFeatureGate: true,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Default dual photo flow configuration
|
|
141
|
+
*/
|
|
142
|
+
export const DEFAULT_DUAL_PHOTO_FLOW: GenerationFlowConfig = {
|
|
143
|
+
photoSteps: [
|
|
144
|
+
{
|
|
145
|
+
enabled: true,
|
|
146
|
+
order: 1,
|
|
147
|
+
id: "partner-a",
|
|
148
|
+
header: {
|
|
149
|
+
showStepIndicator: true,
|
|
150
|
+
currentStep: 1,
|
|
151
|
+
totalSteps: 2,
|
|
152
|
+
titleAlignment: "center",
|
|
153
|
+
titleFontSize: 28,
|
|
154
|
+
subtitleFontSize: 16,
|
|
155
|
+
},
|
|
156
|
+
photoCard: {
|
|
157
|
+
aspectRatio: 1,
|
|
158
|
+
borderRadius: 28,
|
|
159
|
+
showValidationStatus: true,
|
|
160
|
+
allowChange: true,
|
|
161
|
+
borderStyle: "dashed",
|
|
162
|
+
},
|
|
163
|
+
requireNameInput: true,
|
|
164
|
+
enableValidation: false,
|
|
165
|
+
validationType: "none",
|
|
166
|
+
showPhotoTips: true,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
enabled: true,
|
|
170
|
+
order: 2,
|
|
171
|
+
id: "partner-b",
|
|
172
|
+
header: {
|
|
173
|
+
showStepIndicator: true,
|
|
174
|
+
currentStep: 2,
|
|
175
|
+
totalSteps: 2,
|
|
176
|
+
titleAlignment: "center",
|
|
177
|
+
titleFontSize: 28,
|
|
178
|
+
subtitleFontSize: 16,
|
|
179
|
+
},
|
|
180
|
+
photoCard: {
|
|
181
|
+
aspectRatio: 1,
|
|
182
|
+
borderRadius: 28,
|
|
183
|
+
showValidationStatus: true,
|
|
184
|
+
allowChange: true,
|
|
185
|
+
borderStyle: "dashed",
|
|
186
|
+
},
|
|
187
|
+
requireNameInput: true,
|
|
188
|
+
enableValidation: false,
|
|
189
|
+
validationType: "none",
|
|
190
|
+
showPhotoTips: false,
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
behavior: {
|
|
194
|
+
allowBack: true,
|
|
195
|
+
showProgress: true,
|
|
196
|
+
autoAdvance: false,
|
|
197
|
+
requireAuth: false,
|
|
198
|
+
checkFeatureGate: true,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Step data structure
|
|
204
|
+
*/
|
|
205
|
+
export interface PhotoStepData {
|
|
206
|
+
/** Step identifier */
|
|
207
|
+
id: string;
|
|
208
|
+
/** Photo URI */
|
|
209
|
+
imageUri: string | null;
|
|
210
|
+
/** Preview URL */
|
|
211
|
+
previewUrl?: string;
|
|
212
|
+
/** Name/label for this photo */
|
|
213
|
+
name?: string;
|
|
214
|
+
/** Whether validation passed */
|
|
215
|
+
isValid?: boolean;
|
|
216
|
+
/** Validation status */
|
|
217
|
+
validationStatus?: "pending" | "validating" | "valid" | "invalid";
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Text input step data
|
|
222
|
+
*/
|
|
223
|
+
export interface TextInputStepData {
|
|
224
|
+
/** Step identifier */
|
|
225
|
+
id: string;
|
|
226
|
+
/** Text content */
|
|
227
|
+
text: string;
|
|
228
|
+
/** Whether text is valid */
|
|
229
|
+
isValid?: boolean;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Complete flow state
|
|
234
|
+
*/
|
|
235
|
+
export interface GenerationFlowState {
|
|
236
|
+
/** Current step index */
|
|
237
|
+
currentStepIndex: number;
|
|
238
|
+
/** Photo steps data */
|
|
239
|
+
photoSteps: PhotoStepData[];
|
|
240
|
+
/** Text input data */
|
|
241
|
+
textInput?: TextInputStepData;
|
|
242
|
+
/** Whether flow is complete */
|
|
243
|
+
isComplete: boolean;
|
|
244
|
+
/** Whether currently processing */
|
|
245
|
+
isProcessing: boolean;
|
|
246
|
+
}
|