@umituz/react-native-ai-generation-content 1.83.48 → 1.83.50
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 +1 -1
- package/src/domains/generation/wizard/infrastructure/strategies/wizard-strategy.constants.ts +3 -0
- package/src/domains/generation/wizard/infrastructure/utils/creation-persistence-factory.ts +6 -8
- package/src/domains/generation/wizard/infrastructure/utils/creation-persistence.types.ts +0 -4
- package/src/domains/generation/wizard/presentation/hooks/useGenerationHandlers.ts +72 -0
- package/src/domains/generation/wizard/presentation/hooks/useNavigationHandlers.ts +87 -0
- package/src/domains/generation/wizard/presentation/hooks/useWizardFlowHandlers.ts +42 -134
- package/src/domains/generation/wizard/presentation/hooks/wizard-flow-handlers.types.ts +29 -0
- package/src/presentation/components/buttons/GenerateButton.tsx +1 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.83.
|
|
3
|
+
"version": "1.83.50",
|
|
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",
|
package/src/domains/generation/wizard/infrastructure/strategies/wizard-strategy.constants.ts
CHANGED
|
@@ -17,6 +17,9 @@ export const PHOTO_KEY_PREFIX = "photo_";
|
|
|
17
17
|
/** Default style value (no custom style applied) */
|
|
18
18
|
export const DEFAULT_STYLE_VALUE = "original";
|
|
19
19
|
|
|
20
|
+
/** Debounce interval to prevent rapid double-tap on generation start (ms) */
|
|
21
|
+
export const GENERATION_DEBOUNCE_MS = 500;
|
|
22
|
+
|
|
20
23
|
/** Model input defaults */
|
|
21
24
|
export const MODEL_INPUT_DEFAULTS = {
|
|
22
25
|
aspectRatio: "1:1",
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creation Persistence Factory
|
|
3
|
-
*
|
|
3
|
+
* Creates a persistence handler bound to the creations repository
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { createCreationsRepository } from "../../../../creations/infrastructure/adapters";
|
|
7
|
-
import type {
|
|
7
|
+
import type { ProcessingCreationData, CompletedCreationData } from "./creation-persistence.types";
|
|
8
8
|
import { saveAsProcessing } from "./creation-save-operations";
|
|
9
9
|
import { updateToCompleted, updateToFailed, updateRequestId } from "./creation-update-operations";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const { collectionName = "creations" } = config;
|
|
16
|
-
const repository = createCreationsRepository(collectionName);
|
|
11
|
+
const COLLECTION_NAME = "creations";
|
|
12
|
+
|
|
13
|
+
export function createCreationPersistence() {
|
|
14
|
+
const repository = createCreationsRepository(COLLECTION_NAME);
|
|
17
15
|
|
|
18
16
|
return {
|
|
19
17
|
saveAsProcessing: (userId: string, data: ProcessingCreationData) =>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generation-specific handlers: complete, error, dismiss
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useCallback } from "react";
|
|
6
|
+
import { AlertType, AlertMode, useAlert } from "@umituz/react-native-design-system";
|
|
7
|
+
import type { Creation } from "../../../../creations/domain/entities/Creation";
|
|
8
|
+
import { isCreation } from "./typeGuards";
|
|
9
|
+
import { classifyError } from "../../../../../infrastructure/utils/error-classification";
|
|
10
|
+
import type { GenerationErrorInfo } from "../components/WizardFlow.types";
|
|
11
|
+
|
|
12
|
+
interface UseGenerationHandlersProps {
|
|
13
|
+
readonly skipResultStep: boolean;
|
|
14
|
+
readonly t: (key: string) => string;
|
|
15
|
+
readonly nextStep: () => void;
|
|
16
|
+
readonly setResult: (result: unknown) => void;
|
|
17
|
+
readonly setCurrentCreation: (creation: Creation | null) => void;
|
|
18
|
+
readonly onGenerationComplete?: (result: unknown) => void;
|
|
19
|
+
readonly onGenerationError?: (error: string, errorInfo?: GenerationErrorInfo) => void;
|
|
20
|
+
readonly onBack?: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useGenerationHandlers(props: UseGenerationHandlersProps) {
|
|
24
|
+
const { skipResultStep, t, nextStep, setResult, setCurrentCreation, onGenerationComplete, onGenerationError, onBack } = props;
|
|
25
|
+
|
|
26
|
+
const alert = useAlert();
|
|
27
|
+
|
|
28
|
+
const handleGenerationComplete = useCallback(
|
|
29
|
+
(result: unknown) => {
|
|
30
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
31
|
+
console.log("[handleGenerationComplete] Called", { isCreation: isCreation(result), skipResultStep });
|
|
32
|
+
}
|
|
33
|
+
setResult(result);
|
|
34
|
+
setCurrentCreation(isCreation(result) ? result : null);
|
|
35
|
+
onGenerationComplete?.(result);
|
|
36
|
+
if (!skipResultStep) nextStep();
|
|
37
|
+
},
|
|
38
|
+
[setResult, setCurrentCreation, nextStep, onGenerationComplete, skipResultStep],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const handleGenerationError = useCallback(
|
|
42
|
+
(errorMessage: string) => {
|
|
43
|
+
const safeErrorMessage = errorMessage?.trim() || "error.generation.unknown";
|
|
44
|
+
const displayMessage = safeErrorMessage.startsWith("error.") ? t(safeErrorMessage) : safeErrorMessage;
|
|
45
|
+
const errorClassification = classifyError(errorMessage);
|
|
46
|
+
const errorInfo: GenerationErrorInfo = {
|
|
47
|
+
message: safeErrorMessage,
|
|
48
|
+
shouldRefund: errorClassification.retryable ?? false,
|
|
49
|
+
errorType: errorClassification.type,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
53
|
+
console.log("[handleGenerationError] Called", { errorType: errorClassification.type, shouldRefund: errorInfo.shouldRefund });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
alert.show(AlertType.ERROR, AlertMode.MODAL, t("common.error"), displayMessage);
|
|
57
|
+
onGenerationError?.(safeErrorMessage, errorInfo);
|
|
58
|
+
onBack?.();
|
|
59
|
+
},
|
|
60
|
+
[alert, t, onGenerationError, onBack],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const handleDismissGenerating = useCallback(() => {
|
|
64
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
65
|
+
console.log("[handleDismissGenerating] User dismissed generating screen");
|
|
66
|
+
}
|
|
67
|
+
alert.show(AlertType.INFO, AlertMode.TOAST, t("generator.backgroundTitle"), t("generator.backgroundMessage"));
|
|
68
|
+
onBack?.();
|
|
69
|
+
}, [alert, t, onBack]);
|
|
70
|
+
|
|
71
|
+
return { handleGenerationComplete, handleGenerationError, handleDismissGenerating };
|
|
72
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navigation and step transition handlers
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useCallback, useRef } from "react";
|
|
6
|
+
import { StepType, type StepDefinition } from "../../../../../domain/entities/flow-config.types";
|
|
7
|
+
import type { UploadedImage } from "../../../../../presentation/hooks/generation/useAIGenerateState";
|
|
8
|
+
import { GENERATION_DEBOUNCE_MS } from "../../infrastructure/strategies/wizard-strategy.constants";
|
|
9
|
+
|
|
10
|
+
interface UseNavigationHandlersProps {
|
|
11
|
+
readonly currentStepIndex: number;
|
|
12
|
+
readonly flowSteps: StepDefinition[];
|
|
13
|
+
readonly customData: Record<string, unknown>;
|
|
14
|
+
readonly nextStep: () => void;
|
|
15
|
+
readonly previousStep: () => void;
|
|
16
|
+
readonly setCustomData: (stepId: string, data: unknown) => void;
|
|
17
|
+
readonly onGenerationStart?: (data: Record<string, unknown>, proceed: () => void, onError?: (error: string) => void) => void;
|
|
18
|
+
readonly handleGenerationError: (error: string) => void;
|
|
19
|
+
readonly onBack?: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isPlainObjectData(data: unknown): data is Record<string, unknown> {
|
|
23
|
+
return !!data && typeof data === "object" && !("nativeEvent" in data) && !Array.isArray(data);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function useNavigationHandlers(props: UseNavigationHandlersProps) {
|
|
27
|
+
const {
|
|
28
|
+
currentStepIndex, flowSteps, customData, nextStep, previousStep,
|
|
29
|
+
setCustomData, onGenerationStart, handleGenerationError, onBack,
|
|
30
|
+
} = props;
|
|
31
|
+
|
|
32
|
+
const lastGenerationAttemptRef = useRef(0);
|
|
33
|
+
|
|
34
|
+
const handleBack = useCallback(() => {
|
|
35
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
36
|
+
console.log("[handleBack] Called", { currentStepIndex, isFirstStep: currentStepIndex === 0 });
|
|
37
|
+
}
|
|
38
|
+
if (currentStepIndex === 0) onBack?.();
|
|
39
|
+
else previousStep();
|
|
40
|
+
}, [currentStepIndex, previousStep, onBack]);
|
|
41
|
+
|
|
42
|
+
const handleNextStep = useCallback((additionalData?: Record<string, unknown>) => {
|
|
43
|
+
const nextStepDef = flowSteps[currentStepIndex + 1];
|
|
44
|
+
const mergedData = isPlainObjectData(additionalData) ? { ...customData, ...additionalData } : customData;
|
|
45
|
+
|
|
46
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
47
|
+
console.log("[handleNextStep] Called", {
|
|
48
|
+
currentStepIndex,
|
|
49
|
+
nextStepType: nextStepDef?.type,
|
|
50
|
+
nextStepId: nextStepDef?.id,
|
|
51
|
+
totalSteps: flowSteps.length,
|
|
52
|
+
hasOnGenerationStart: !!onGenerationStart,
|
|
53
|
+
dataKeys: Object.keys(mergedData),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (nextStepDef?.type === StepType.GENERATING && onGenerationStart) {
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
if (now - lastGenerationAttemptRef.current < GENERATION_DEBOUNCE_MS) {
|
|
60
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
61
|
+
console.log("[handleNextStep] Debounced - too rapid");
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
lastGenerationAttemptRef.current = now;
|
|
66
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
67
|
+
console.log("[handleNextStep] Calling onGenerationStart");
|
|
68
|
+
}
|
|
69
|
+
onGenerationStart(mergedData, nextStep, handleGenerationError);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
nextStep();
|
|
73
|
+
}, [currentStepIndex, flowSteps, customData, onGenerationStart, nextStep, handleGenerationError]);
|
|
74
|
+
|
|
75
|
+
const handlePhotoContinue = useCallback(
|
|
76
|
+
(stepId: string, image: UploadedImage) => {
|
|
77
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
78
|
+
console.log("[handlePhotoContinue] Called", { stepId, hasImage: !!image, currentStepIndex });
|
|
79
|
+
}
|
|
80
|
+
setCustomData(stepId, image);
|
|
81
|
+
handleNextStep({ [stepId]: image });
|
|
82
|
+
},
|
|
83
|
+
[setCustomData, handleNextStep, currentStepIndex],
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return { handleBack, handleNextStep, handlePhotoContinue };
|
|
87
|
+
}
|
|
@@ -1,161 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import type { Creation } from "../../../../creations/domain/entities/Creation";
|
|
6
|
-
import { isCreation } from "./typeGuards";
|
|
7
|
-
import { classifyError } from "../../../../../infrastructure/utils/error-classification";
|
|
8
|
-
import type { GenerationErrorInfo } from "../components/WizardFlow.types";
|
|
1
|
+
/**
|
|
2
|
+
* Wizard Flow Handlers - Composition Hook
|
|
3
|
+
* Combines generation, navigation, and rating handlers
|
|
4
|
+
*/
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
readonly userId?: string;
|
|
16
|
-
readonly currentCreation: Creation | null;
|
|
17
|
-
readonly repository: { rate: (uid: string, id: string, rating: number, desc: string) => Promise<boolean> };
|
|
18
|
-
readonly t: (key: string) => string;
|
|
19
|
-
readonly nextStep: () => void;
|
|
20
|
-
readonly previousStep: () => void;
|
|
21
|
-
readonly setResult: (result: unknown) => void;
|
|
22
|
-
readonly setCustomData: (stepId: string, data: unknown) => void;
|
|
23
|
-
readonly setCurrentCreation: (creation: Creation | null) => void;
|
|
24
|
-
readonly setHasRated: (hasRated: boolean) => void;
|
|
25
|
-
readonly setShowRatingPicker: (show: boolean) => void;
|
|
26
|
-
readonly onGenerationStart?: (data: Record<string, unknown>, proceed: () => void, onError?: (error: string) => void) => void;
|
|
27
|
-
readonly onGenerationComplete?: (result: unknown) => void;
|
|
28
|
-
readonly onGenerationError?: (error: string, errorInfo?: GenerationErrorInfo) => void;
|
|
29
|
-
readonly onBack?: () => void;
|
|
30
|
-
}
|
|
6
|
+
import { useCallback } from "react";
|
|
7
|
+
import { AlertType, AlertMode, useAlert } from "@umituz/react-native-design-system";
|
|
8
|
+
import type { UseWizardFlowHandlersProps } from "./wizard-flow-handlers.types";
|
|
9
|
+
import { useGenerationHandlers } from "./useGenerationHandlers";
|
|
10
|
+
import { useNavigationHandlers } from "./useNavigationHandlers";
|
|
31
11
|
|
|
32
12
|
export function useWizardFlowHandlers(props: UseWizardFlowHandlersProps) {
|
|
33
13
|
const {
|
|
14
|
+
currentStepIndex, flowSteps, customData, userId, currentCreation,
|
|
15
|
+
repository, t, nextStep, previousStep, setCustomData,
|
|
16
|
+
onGenerationStart, onBack,
|
|
17
|
+
} = props;
|
|
18
|
+
|
|
19
|
+
const alert = useAlert();
|
|
20
|
+
|
|
21
|
+
const generation = useGenerationHandlers({
|
|
22
|
+
skipResultStep: props.skipResultStep,
|
|
23
|
+
t,
|
|
24
|
+
nextStep,
|
|
25
|
+
setResult: props.setResult,
|
|
26
|
+
setCurrentCreation: props.setCurrentCreation,
|
|
27
|
+
onGenerationComplete: props.onGenerationComplete,
|
|
28
|
+
onGenerationError: props.onGenerationError,
|
|
29
|
+
onBack,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const navigation = useNavigationHandlers({
|
|
34
33
|
currentStepIndex,
|
|
35
34
|
flowSteps,
|
|
36
35
|
customData,
|
|
37
|
-
skipResultStep,
|
|
38
|
-
userId,
|
|
39
|
-
currentCreation,
|
|
40
|
-
repository,
|
|
41
|
-
t,
|
|
42
36
|
nextStep,
|
|
43
37
|
previousStep,
|
|
44
|
-
setResult,
|
|
45
38
|
setCustomData,
|
|
46
|
-
setCurrentCreation,
|
|
47
|
-
setHasRated,
|
|
48
|
-
setShowRatingPicker,
|
|
49
39
|
onGenerationStart,
|
|
50
|
-
|
|
51
|
-
onGenerationError,
|
|
40
|
+
handleGenerationError: generation.handleGenerationError,
|
|
52
41
|
onBack,
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const alert = useAlert();
|
|
56
|
-
// Guard: prevent multiple onGenerationStart calls from auto-advancing steps
|
|
57
|
-
const generationStartedRef = useRef(false);
|
|
58
|
-
|
|
59
|
-
const handleGenerationComplete = useCallback(
|
|
60
|
-
(result: unknown) => {
|
|
61
|
-
generationStartedRef.current = false;
|
|
62
|
-
setResult(result);
|
|
63
|
-
setCurrentCreation(isCreation(result) ? result : null);
|
|
64
|
-
onGenerationComplete?.(result);
|
|
65
|
-
if (!skipResultStep) nextStep();
|
|
66
|
-
},
|
|
67
|
-
[setResult, setCurrentCreation, nextStep, onGenerationComplete, skipResultStep],
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
const handleGenerationError = useCallback(
|
|
71
|
-
(errorMessage: string) => {
|
|
72
|
-
generationStartedRef.current = false;
|
|
73
|
-
const safeErrorMessage = errorMessage?.trim() || "error.generation.unknown";
|
|
74
|
-
const displayMessage = safeErrorMessage.startsWith("error.") ? t(safeErrorMessage) : safeErrorMessage;
|
|
75
|
-
|
|
76
|
-
// Classify error to determine refund eligibility
|
|
77
|
-
const errorClassification = classifyError(errorMessage);
|
|
78
|
-
const errorInfo: GenerationErrorInfo = {
|
|
79
|
-
message: safeErrorMessage,
|
|
80
|
-
shouldRefund: errorClassification.retryable ?? false,
|
|
81
|
-
errorType: errorClassification.type,
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
alert.show(AlertType.ERROR, AlertMode.MODAL, t("common.error"), displayMessage);
|
|
85
|
-
onGenerationError?.(safeErrorMessage, errorInfo);
|
|
86
|
-
onBack?.();
|
|
87
|
-
},
|
|
88
|
-
[alert, t, onGenerationError, onBack],
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
const handleDismissGenerating = useCallback(() => {
|
|
92
|
-
alert.show(AlertType.INFO, AlertMode.TOAST, t("generator.backgroundTitle"), t("generator.backgroundMessage"));
|
|
93
|
-
onBack?.();
|
|
94
|
-
}, [alert, t, onBack]);
|
|
95
|
-
|
|
96
|
-
const handleBack = useCallback(() => {
|
|
97
|
-
if (currentStepIndex === 0) onBack?.();
|
|
98
|
-
else previousStep();
|
|
99
|
-
}, [currentStepIndex, previousStep, onBack]);
|
|
100
|
-
|
|
101
|
-
const handleNextStep = useCallback((additionalData?: Record<string, unknown>) => {
|
|
102
|
-
const nextStepDef = flowSteps[currentStepIndex + 1];
|
|
103
|
-
// Merge additionalData to avoid stale closure issue
|
|
104
|
-
// When called from handlePhotoContinue, customData in closure may not include the just-set value
|
|
105
|
-
// Guard: Only merge plain objects (ignore SyntheticEvents from onPress handlers)
|
|
106
|
-
const isPlainObject = additionalData && typeof additionalData === "object" && !("nativeEvent" in additionalData) && !Array.isArray(additionalData);
|
|
107
|
-
const mergedData = isPlainObject ? { ...customData, ...additionalData } : customData;
|
|
108
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
109
|
-
console.log("[handleNextStep] Called", {
|
|
110
|
-
currentStepIndex,
|
|
111
|
-
nextStepType: nextStepDef?.type,
|
|
112
|
-
nextStepId: nextStepDef?.id,
|
|
113
|
-
totalSteps: flowSteps.length,
|
|
114
|
-
hasOnGenerationStart: !!onGenerationStart,
|
|
115
|
-
dataKeys: Object.keys(mergedData),
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
if (nextStepDef?.type === StepType.GENERATING && onGenerationStart) {
|
|
119
|
-
if (generationStartedRef.current) return;
|
|
120
|
-
generationStartedRef.current = true;
|
|
121
|
-
onGenerationStart(mergedData, nextStep, handleGenerationError);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
nextStep();
|
|
125
|
-
}, [currentStepIndex, flowSteps, customData, onGenerationStart, nextStep, handleGenerationError]);
|
|
126
|
-
|
|
127
|
-
const handlePhotoContinue = useCallback(
|
|
128
|
-
(stepId: string, image: UploadedImage) => {
|
|
129
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
130
|
-
console.log("[handlePhotoContinue] Called", { stepId, hasImage: !!image, currentStepIndex });
|
|
131
|
-
}
|
|
132
|
-
setCustomData(stepId, image);
|
|
133
|
-
// Pass the just-set data to avoid stale closure issue
|
|
134
|
-
handleNextStep({ [stepId]: image });
|
|
135
|
-
},
|
|
136
|
-
[setCustomData, handleNextStep, currentStepIndex],
|
|
137
|
-
);
|
|
42
|
+
});
|
|
138
43
|
|
|
139
44
|
const handleSubmitRating = useCallback(
|
|
140
45
|
async (rating: number, description: string) => {
|
|
141
46
|
if (!currentCreation?.id || !userId) return;
|
|
47
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
48
|
+
console.log("[handleSubmitRating] Called", { creationId: currentCreation.id, rating });
|
|
49
|
+
}
|
|
142
50
|
const success = await repository.rate(userId, currentCreation.id, rating, description);
|
|
143
51
|
if (success) {
|
|
144
|
-
setHasRated(true);
|
|
52
|
+
props.setHasRated(true);
|
|
145
53
|
alert.show(AlertType.SUCCESS, AlertMode.TOAST, t("result.rateSuccessTitle"), t("result.rateSuccessMessage"));
|
|
146
54
|
}
|
|
147
|
-
setShowRatingPicker(false);
|
|
55
|
+
props.setShowRatingPicker(false);
|
|
148
56
|
},
|
|
149
|
-
[currentCreation, userId, repository, alert, t, setHasRated, setShowRatingPicker],
|
|
57
|
+
[currentCreation, userId, repository, alert, t, props.setHasRated, props.setShowRatingPicker],
|
|
150
58
|
);
|
|
151
59
|
|
|
152
60
|
return {
|
|
153
|
-
handleGenerationComplete,
|
|
154
|
-
handleGenerationError,
|
|
155
|
-
handleDismissGenerating,
|
|
156
|
-
handleBack,
|
|
157
|
-
handleNextStep,
|
|
158
|
-
handlePhotoContinue,
|
|
61
|
+
handleGenerationComplete: generation.handleGenerationComplete,
|
|
62
|
+
handleGenerationError: generation.handleGenerationError,
|
|
63
|
+
handleDismissGenerating: generation.handleDismissGenerating,
|
|
64
|
+
handleBack: navigation.handleBack,
|
|
65
|
+
handleNextStep: navigation.handleNextStep,
|
|
66
|
+
handlePhotoContinue: navigation.handlePhotoContinue,
|
|
159
67
|
handleSubmitRating,
|
|
160
68
|
};
|
|
161
69
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for Wizard Flow Handlers
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { StepDefinition } from "../../../../../domain/entities/flow-config.types";
|
|
6
|
+
import type { Creation } from "../../../../creations/domain/entities/Creation";
|
|
7
|
+
import type { GenerationErrorInfo } from "../components/WizardFlow.types";
|
|
8
|
+
|
|
9
|
+
export interface UseWizardFlowHandlersProps {
|
|
10
|
+
readonly currentStepIndex: number;
|
|
11
|
+
readonly flowSteps: StepDefinition[];
|
|
12
|
+
readonly customData: Record<string, unknown>;
|
|
13
|
+
readonly skipResultStep: boolean;
|
|
14
|
+
readonly userId?: string;
|
|
15
|
+
readonly currentCreation: Creation | null;
|
|
16
|
+
readonly repository: { rate: (uid: string, id: string, rating: number, desc: string) => Promise<boolean> };
|
|
17
|
+
readonly t: (key: string) => string;
|
|
18
|
+
readonly nextStep: () => void;
|
|
19
|
+
readonly previousStep: () => void;
|
|
20
|
+
readonly setResult: (result: unknown) => void;
|
|
21
|
+
readonly setCustomData: (stepId: string, data: unknown) => void;
|
|
22
|
+
readonly setCurrentCreation: (creation: Creation | null) => void;
|
|
23
|
+
readonly setHasRated: (hasRated: boolean) => void;
|
|
24
|
+
readonly setShowRatingPicker: (show: boolean) => void;
|
|
25
|
+
readonly onGenerationStart?: (data: Record<string, unknown>, proceed: () => void, onError?: (error: string) => void) => void;
|
|
26
|
+
readonly onGenerationComplete?: (result: unknown) => void;
|
|
27
|
+
readonly onGenerationError?: (error: string, errorInfo?: GenerationErrorInfo) => void;
|
|
28
|
+
readonly onBack?: () => void;
|
|
29
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Props-driven for 100+ apps compatibility
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React
|
|
7
|
+
import React from "react";
|
|
8
8
|
import { View, StyleSheet, TouchableOpacity, type ViewStyle } from "react-native";
|
|
9
9
|
import {
|
|
10
10
|
AtomicText,
|
|
@@ -41,25 +41,12 @@ export const GenerateButton: React.FC<GenerateButtonProps> = ({
|
|
|
41
41
|
onAccessoryRightPress,
|
|
42
42
|
style,
|
|
43
43
|
}) => {
|
|
44
|
-
if (__DEV__) {
|
|
45
|
-
console.log("[GenerateButton] RENDERING NOW");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
44
|
const tokens = useAppDesignTokens();
|
|
49
45
|
const disabled = isDisabled || isProcessing;
|
|
50
46
|
const displayText = isProcessing && processingText ? processingText : text;
|
|
51
47
|
const finalDisplayText = costLabel ? `${displayText} (${costLabel})` : displayText;
|
|
52
48
|
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (__DEV__) {
|
|
55
|
-
console.log("[GenerateButton] MOUNTED/UPDATED - isDisabled:", isDisabled, "isProcessing:", isProcessing, "disabled:", disabled, "text:", text);
|
|
56
|
-
}
|
|
57
|
-
}, [isDisabled, isProcessing, disabled, text]);
|
|
58
|
-
|
|
59
49
|
const handlePress = () => {
|
|
60
|
-
if (__DEV__) {
|
|
61
|
-
console.log("[GenerateButton] PRESSED - disabled:", disabled, "isDisabled:", isDisabled, "isProcessing:", isProcessing);
|
|
62
|
-
}
|
|
63
50
|
if (!disabled) {
|
|
64
51
|
onPress();
|
|
65
52
|
}
|