@umituz/react-native-ai-generation-content 1.17.143 → 1.17.145

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 (43) hide show
  1. package/package.json +1 -1
  2. package/src/domains/creations/presentation/hooks/index.ts +2 -2
  3. package/src/domains/creations/presentation/hooks/{useMediaFilter.ts → useFilter.ts} +12 -7
  4. package/src/domains/creations/presentation/hooks/useGalleryFilters.ts +5 -6
  5. package/src/features/ai-hug/presentation/hooks/useAIHugFeature.ts +9 -113
  6. package/src/features/ai-kiss/presentation/hooks/useAIKissFeature.ts +9 -113
  7. package/src/features/image-to-video/infrastructure/services/image-to-video-executor.ts +5 -9
  8. package/src/features/image-to-video/presentation/hooks/useImageToVideoForm.ts +5 -0
  9. package/src/features/replace-background/index.ts +5 -50
  10. package/src/features/replace-background/presentation/components/index.ts +0 -12
  11. package/src/features/replace-background/presentation/hooks/index.ts +0 -3
  12. package/src/features/shared/dual-image-video/domain/types/dual-image-video.types.ts +67 -0
  13. package/src/features/shared/dual-image-video/domain/types/index.ts +13 -0
  14. package/src/features/shared/dual-image-video/index.ts +16 -0
  15. package/src/features/shared/dual-image-video/presentation/hooks/index.ts +5 -0
  16. package/src/features/shared/dual-image-video/presentation/hooks/useDualImageVideoFeature.ts +124 -0
  17. package/src/features/shared/index.ts +6 -0
  18. package/src/infrastructure/utils/index.ts +1 -0
  19. package/src/infrastructure/utils/progress-calculator.util.ts +31 -0
  20. package/src/infrastructure/utils/result-validator.util.ts +0 -214
  21. package/src/infrastructure/utils/url-extractor.util.ts +209 -0
  22. package/src/presentation/hooks/flow-state.utils.ts +101 -0
  23. package/src/presentation/hooks/useGenerationFlow.ts +47 -178
  24. package/src/presentation/types/flow-config.types.ts +5 -99
  25. package/src/presentation/types/flow-default-configs.ts +106 -0
  26. package/src/domains/creations/presentation/hooks/useStatusFilter.ts +0 -54
  27. package/src/features/replace-background/domain/entities/background.types.ts +0 -77
  28. package/src/features/replace-background/domain/entities/component.types.ts +0 -87
  29. package/src/features/replace-background/domain/entities/config.types.ts +0 -41
  30. package/src/features/replace-background/domain/entities/index.ts +0 -30
  31. package/src/features/replace-background/infrastructure/constants/index.ts +0 -5
  32. package/src/features/replace-background/infrastructure/constants/prompts.constants.ts +0 -15
  33. package/src/features/replace-background/infrastructure/index.ts +0 -5
  34. package/src/features/replace-background/presentation/components/BackgroundFeature.tsx +0 -143
  35. package/src/features/replace-background/presentation/components/ComparisonSlider.tsx +0 -187
  36. package/src/features/replace-background/presentation/components/ErrorDisplay.tsx +0 -60
  37. package/src/features/replace-background/presentation/components/FeatureHeader.tsx +0 -80
  38. package/src/features/replace-background/presentation/components/GenerateButton.tsx +0 -85
  39. package/src/features/replace-background/presentation/components/ImagePicker.tsx +0 -136
  40. package/src/features/replace-background/presentation/components/ModeSelector.tsx +0 -78
  41. package/src/features/replace-background/presentation/components/PromptInput.tsx +0 -142
  42. package/src/features/replace-background/presentation/components/ResultDisplay.tsx +0 -122
  43. package/src/features/replace-background/presentation/hooks/useBackgroundFeature.ts +0 -119
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Flow State Utilities
3
+ * State initialization and update helpers for generation flow
4
+ *
5
+ * @package @umituz/react-native-ai-generation-content
6
+ */
7
+
8
+ import type {
9
+ GenerationFlowConfig,
10
+ GenerationFlowState,
11
+ PhotoStepData,
12
+ PhotoStepConfig,
13
+ } from "../types/flow-config.types";
14
+
15
+ /**
16
+ * Create initial flow state from config
17
+ */
18
+ export function createInitialFlowState(
19
+ config: GenerationFlowConfig,
20
+ ): GenerationFlowState {
21
+ return {
22
+ currentStepIndex: 0,
23
+ photoSteps: config.photoSteps.map((step) => ({
24
+ id: step.id,
25
+ imageUri: null,
26
+ previewUrl: undefined,
27
+ name: undefined,
28
+ isValid: undefined,
29
+ validationStatus: "pending" as const,
30
+ })),
31
+ textInput: config.textInputStep
32
+ ? {
33
+ id: config.textInputStep.id,
34
+ text: "",
35
+ isValid: false,
36
+ }
37
+ : undefined,
38
+ isComplete: false,
39
+ isProcessing: false,
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Update photo step in state
45
+ */
46
+ export function updatePhotoStep(
47
+ state: GenerationFlowState,
48
+ stepIndex: number,
49
+ updates: Partial<PhotoStepData>,
50
+ ): GenerationFlowState {
51
+ const newPhotoSteps = [...state.photoSteps];
52
+ newPhotoSteps[stepIndex] = {
53
+ ...newPhotoSteps[stepIndex],
54
+ ...updates,
55
+ };
56
+
57
+ return {
58
+ ...state,
59
+ photoSteps: newPhotoSteps,
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Check if current step is valid
65
+ */
66
+ export function isStepValid(
67
+ stepData: PhotoStepData | null,
68
+ stepConfig: PhotoStepConfig | null,
69
+ ): boolean {
70
+ if (!stepData || !stepConfig) {
71
+ return false;
72
+ }
73
+
74
+ // Check photo
75
+ if (!stepData.imageUri) {
76
+ return false;
77
+ }
78
+
79
+ // Check name if required
80
+ if (stepConfig.requireNameInput && !stepData.name) {
81
+ return false;
82
+ }
83
+
84
+ // Check validation if enabled
85
+ if (stepConfig.enableValidation && !stepData.isValid) {
86
+ return false;
87
+ }
88
+
89
+ return true;
90
+ }
91
+
92
+ /**
93
+ * Check if text input is valid
94
+ */
95
+ export function isTextInputValid(
96
+ text: string,
97
+ minLength: number,
98
+ maxLength: number,
99
+ ): boolean {
100
+ return text.length >= minLength && text.length <= maxLength;
101
+ }
@@ -12,42 +12,32 @@ import type {
12
12
  PhotoStepData,
13
13
  PhotoStepConfig,
14
14
  } from "../types/flow-config.types";
15
+ import {
16
+ createInitialFlowState,
17
+ updatePhotoStep,
18
+ isStepValid,
19
+ isTextInputValid,
20
+ } from "./flow-state.utils";
15
21
 
16
22
  export interface UseGenerationFlowOptions {
17
- /** Flow configuration */
18
23
  config: GenerationFlowConfig;
19
- /** Callback when flow is complete */
20
24
  onComplete?: (state: GenerationFlowState) => void;
21
- /** Callback when step changes */
22
25
  onStepChange?: (stepIndex: number, stepConfig: PhotoStepConfig) => void;
23
26
  }
24
27
 
25
28
  export interface UseGenerationFlowReturn {
26
- /** Current flow state */
27
29
  state: GenerationFlowState;
28
- /** Current step configuration */
29
30
  currentStepConfig: PhotoStepConfig | null;
30
- /** Current step data */
31
31
  currentStepData: PhotoStepData | null;
32
- /** Whether can go to next step */
33
32
  canGoNext: boolean;
34
- /** Whether can go to previous step */
35
33
  canGoBack: boolean;
36
- /** Go to next step */
37
34
  goNext: () => void;
38
- /** Go to previous step */
39
35
  goBack: () => void;
40
- /** Update current step photo */
41
36
  updatePhoto: (imageUri: string, previewUrl?: string) => void;
42
- /** Update current step name */
43
37
  updateName: (name: string) => void;
44
- /** Update current step validation */
45
38
  updateValidation: (isValid: boolean) => void;
46
- /** Update text input */
47
39
  updateTextInput: (text: string) => void;
48
- /** Reset flow */
49
40
  reset: () => void;
50
- /** Complete flow */
51
41
  complete: () => void;
52
42
  }
53
43
 
@@ -59,186 +49,90 @@ export const useGenerationFlow = ({
59
49
  onComplete,
60
50
  onStepChange,
61
51
  }: 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
- }));
52
+ const [state, setState] = useState<GenerationFlowState>(() =>
53
+ createInitialFlowState(config),
54
+ );
83
55
 
84
- // Get current step configuration
85
56
  const currentStepConfig = useMemo(() => {
86
- if (state.currentStepIndex >= config.photoSteps.length) {
87
- return null;
88
- }
57
+ if (state.currentStepIndex >= config.photoSteps.length) return null;
89
58
  return config.photoSteps[state.currentStepIndex];
90
59
  }, [state.currentStepIndex, config.photoSteps]);
91
60
 
92
- // Get current step data
93
61
  const currentStepData = useMemo(() => {
94
- if (state.currentStepIndex >= state.photoSteps.length) {
95
- return null;
96
- }
62
+ if (state.currentStepIndex >= state.photoSteps.length) return null;
97
63
  return state.photoSteps[state.currentStepIndex];
98
64
  }, [state.currentStepIndex, state.photoSteps]);
99
65
 
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]);
66
+ const isCurrentStepValid = useMemo(
67
+ () => isStepValid(currentStepData, currentStepConfig),
68
+ [currentStepData, currentStepConfig],
69
+ );
123
70
 
124
- // Can go to next step
125
- const canGoNext = useMemo(() => {
126
- return isCurrentStepValid && !state.isProcessing;
127
- }, [isCurrentStepValid, state.isProcessing]);
71
+ const canGoNext = useMemo(
72
+ () => isCurrentStepValid && !state.isProcessing,
73
+ [isCurrentStepValid, state.isProcessing],
74
+ );
128
75
 
129
- // Can go back
130
- const canGoBack = useMemo(() => {
131
- return (
76
+ const canGoBack = useMemo(
77
+ () =>
132
78
  state.currentStepIndex > 0 &&
133
79
  config.behavior?.allowBack !== false &&
134
- !state.isProcessing
135
- );
136
- }, [state.currentStepIndex, config.behavior?.allowBack, state.isProcessing]);
80
+ !state.isProcessing,
81
+ [state.currentStepIndex, config.behavior?.allowBack, state.isProcessing],
82
+ );
137
83
 
138
- // Go to next step
139
84
  const goNext = useCallback(() => {
140
85
  if (!canGoNext) return;
141
86
 
142
87
  setState((prev) => {
143
88
  const nextIndex = prev.currentStepIndex + 1;
144
89
 
145
- // If we've completed all photo steps, mark as complete
146
90
  if (nextIndex >= config.photoSteps.length) {
147
- const newState = {
148
- ...prev,
149
- isComplete: true,
150
- };
91
+ const newState = { ...prev, isComplete: true };
151
92
  onComplete?.(newState);
152
93
  return newState;
153
94
  }
154
95
 
155
- // Move to next step
156
- const newState = {
157
- ...prev,
158
- currentStepIndex: nextIndex,
159
- };
160
-
161
- // Notify step change
162
96
  onStepChange?.(nextIndex, config.photoSteps[nextIndex]);
163
-
164
- return newState;
97
+ return { ...prev, currentStepIndex: nextIndex };
165
98
  });
166
99
  }, [canGoNext, config.photoSteps, onComplete, onStepChange]);
167
100
 
168
- // Go to previous step
169
101
  const goBack = useCallback(() => {
170
102
  if (!canGoBack) return;
171
103
 
172
104
  setState((prev) => {
173
105
  const prevIndex = prev.currentStepIndex - 1;
174
- const newState = {
175
- ...prev,
176
- currentStepIndex: prevIndex,
177
- isComplete: false,
178
- };
179
-
180
- // Notify step change
181
106
  onStepChange?.(prevIndex, config.photoSteps[prevIndex]);
182
-
183
- return newState;
107
+ return { ...prev, currentStepIndex: prevIndex, isComplete: false };
184
108
  });
185
109
  }, [canGoBack, config.photoSteps, onStepChange]);
186
110
 
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
- );
111
+ const updatePhoto = useCallback((imageUri: string, previewUrl?: string) => {
112
+ setState((prev) =>
113
+ updatePhotoStep(prev, prev.currentStepIndex, {
114
+ imageUri,
115
+ previewUrl,
116
+ validationStatus: "pending",
117
+ }),
118
+ );
119
+ }, []);
207
120
 
208
- // Update name
209
121
  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
- });
122
+ setState((prev) =>
123
+ updatePhotoStep(prev, prev.currentStepIndex, { name }),
124
+ );
222
125
  }, []);
223
126
 
224
- // Update validation
225
127
  const updateValidation = useCallback((isValid: boolean) => {
226
- setState((prev) => {
227
- const newPhotoSteps = [...prev.photoSteps];
228
- newPhotoSteps[prev.currentStepIndex] = {
229
- ...newPhotoSteps[prev.currentStepIndex],
128
+ setState((prev) =>
129
+ updatePhotoStep(prev, prev.currentStepIndex, {
230
130
  isValid,
231
131
  validationStatus: isValid ? "valid" : "invalid",
232
- };
233
-
234
- return {
235
- ...prev,
236
- photoSteps: newPhotoSteps,
237
- };
238
- });
132
+ }),
133
+ );
239
134
  }, []);
240
135
 
241
- // Update text input
242
136
  const updateTextInput = useCallback(
243
137
  (text: string) => {
244
138
  setState((prev) => {
@@ -246,14 +140,13 @@ export const useGenerationFlow = ({
246
140
 
247
141
  const minLength = config.textInputStep?.minLength ?? 0;
248
142
  const maxLength = config.textInputStep?.maxLength ?? Infinity;
249
- const isValid = text.length >= minLength && text.length <= maxLength;
250
143
 
251
144
  return {
252
145
  ...prev,
253
146
  textInput: {
254
147
  ...prev.textInput,
255
148
  text,
256
- isValid,
149
+ isValid: isTextInputValid(text, minLength, maxLength),
257
150
  },
258
151
  };
259
152
  });
@@ -261,37 +154,13 @@ export const useGenerationFlow = ({
261
154
  [config.textInputStep],
262
155
  );
263
156
 
264
- // Reset flow
265
157
  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]);
158
+ setState(createInitialFlowState(config));
159
+ }, [config]);
287
160
 
288
- // Complete flow
289
161
  const complete = useCallback(() => {
290
162
  setState((prev) => {
291
- const newState = {
292
- ...prev,
293
- isComplete: true,
294
- };
163
+ const newState = { ...prev, isComplete: true };
295
164
  onComplete?.(newState);
296
165
  return newState;
297
166
  });
@@ -99,105 +99,11 @@ export interface GenerationFlowConfig {
99
99
  };
100
100
  }
101
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
- };
102
+ // Re-export default configs from separate file
103
+ export {
104
+ DEFAULT_SINGLE_PHOTO_FLOW,
105
+ DEFAULT_DUAL_PHOTO_FLOW,
106
+ } from "./flow-default-configs";
201
107
 
202
108
  /**
203
109
  * Step data structure
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Flow Default Configurations
3
+ * Default configurations for generation flows
4
+ */
5
+
6
+ import type { GenerationFlowConfig } from "./flow-config.types";
7
+
8
+ /**
9
+ * Default single photo flow configuration
10
+ */
11
+ export const DEFAULT_SINGLE_PHOTO_FLOW: GenerationFlowConfig = {
12
+ photoSteps: [
13
+ {
14
+ enabled: true,
15
+ order: 1,
16
+ id: "photo-1",
17
+ header: {
18
+ showStepIndicator: false,
19
+ titleAlignment: "center",
20
+ titleFontSize: 28,
21
+ subtitleFontSize: 16,
22
+ },
23
+ photoCard: {
24
+ aspectRatio: 1,
25
+ borderRadius: 28,
26
+ showValidationStatus: true,
27
+ allowChange: true,
28
+ borderStyle: "dashed",
29
+ },
30
+ requireNameInput: true,
31
+ enableValidation: false,
32
+ validationType: "none",
33
+ showPhotoTips: true,
34
+ },
35
+ ],
36
+ behavior: {
37
+ allowBack: false,
38
+ showProgress: false,
39
+ autoAdvance: false,
40
+ requireAuth: false,
41
+ checkFeatureGate: true,
42
+ },
43
+ };
44
+
45
+ /**
46
+ * Default dual photo flow configuration
47
+ */
48
+ export const DEFAULT_DUAL_PHOTO_FLOW: GenerationFlowConfig = {
49
+ photoSteps: [
50
+ {
51
+ enabled: true,
52
+ order: 1,
53
+ id: "partner-a",
54
+ header: {
55
+ showStepIndicator: true,
56
+ currentStep: 1,
57
+ totalSteps: 2,
58
+ titleAlignment: "center",
59
+ titleFontSize: 28,
60
+ subtitleFontSize: 16,
61
+ },
62
+ photoCard: {
63
+ aspectRatio: 1,
64
+ borderRadius: 28,
65
+ showValidationStatus: true,
66
+ allowChange: true,
67
+ borderStyle: "dashed",
68
+ },
69
+ requireNameInput: true,
70
+ enableValidation: false,
71
+ validationType: "none",
72
+ showPhotoTips: true,
73
+ },
74
+ {
75
+ enabled: true,
76
+ order: 2,
77
+ id: "partner-b",
78
+ header: {
79
+ showStepIndicator: true,
80
+ currentStep: 2,
81
+ totalSteps: 2,
82
+ titleAlignment: "center",
83
+ titleFontSize: 28,
84
+ subtitleFontSize: 16,
85
+ },
86
+ photoCard: {
87
+ aspectRatio: 1,
88
+ borderRadius: 28,
89
+ showValidationStatus: true,
90
+ allowChange: true,
91
+ borderStyle: "dashed",
92
+ },
93
+ requireNameInput: true,
94
+ enableValidation: false,
95
+ validationType: "none",
96
+ showPhotoTips: false,
97
+ },
98
+ ],
99
+ behavior: {
100
+ allowBack: true,
101
+ showProgress: true,
102
+ autoAdvance: false,
103
+ requireAuth: false,
104
+ checkFeatureGate: true,
105
+ },
106
+ };
@@ -1,54 +0,0 @@
1
- /**
2
- * useStatusFilter Hook
3
- * Handles status filtering (completed, pending, processing, failed)
4
- * SOLID: Single Responsibility - Only handles status filter state
5
- */
6
-
7
- import { useState, useCallback, useMemo } from "react";
8
- import type { FilterOption } from "../../domain/types/creation-filter";
9
-
10
- interface UseStatusFilterProps {
11
- readonly options: FilterOption[];
12
- readonly t: (key: string) => string;
13
- readonly defaultId?: string;
14
- }
15
-
16
- interface UseStatusFilterReturn {
17
- readonly selectedId: string;
18
- readonly filterOptions: FilterOption[];
19
- readonly hasActiveFilter: boolean;
20
- readonly selectFilter: (id: string) => void;
21
- readonly clearFilter: () => void;
22
- }
23
-
24
- export function useStatusFilter({
25
- options,
26
- t,
27
- defaultId = "all"
28
- }: UseStatusFilterProps): UseStatusFilterReturn {
29
- const [selectedId, setSelectedId] = useState(defaultId);
30
-
31
- const filterOptions = useMemo(() =>
32
- options.map(opt => ({
33
- ...opt,
34
- label: opt.labelKey ? t(opt.labelKey) : opt.label
35
- })),
36
- [options, t]
37
- );
38
-
39
- const selectFilter = useCallback((id: string) => {
40
- setSelectedId(id);
41
- }, []);
42
-
43
- const clearFilter = useCallback(() => {
44
- setSelectedId(defaultId);
45
- }, [defaultId]);
46
-
47
- return {
48
- selectedId,
49
- filterOptions,
50
- hasActiveFilter: selectedId !== defaultId,
51
- selectFilter,
52
- clearFilter
53
- };
54
- }