@umituz/react-native-ai-generation-content 1.17.219 → 1.17.221
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/creations/presentation/components/CreationCard.tsx +19 -145
- package/src/domains/creations/presentation/components/CreationCard.types.ts +58 -0
- package/src/domains/creations/presentation/components/CreationCard.utils.ts +29 -0
- package/src/domains/creations/presentation/components/CreationCardMeta.tsx +50 -0
- package/src/domains/creations/presentation/components/CreationsFilterBar.helpers.ts +96 -0
- package/src/domains/creations/presentation/components/CreationsFilterBar.tsx +6 -121
- package/src/domains/creations/presentation/components/CreationsFilterBar.types.ts +47 -0
- package/src/domains/creations/presentation/components/useCreationCardActions.ts +73 -0
- package/src/features/image-to-video/presentation/components/AddMoreCard.tsx +52 -0
- package/src/features/image-to-video/presentation/components/EmptyGridState.tsx +69 -0
- package/src/features/image-to-video/presentation/components/GridImageItem.tsx +64 -0
- package/src/features/image-to-video/presentation/components/ImageSelectionGrid.styles.ts +84 -0
- package/src/features/image-to-video/presentation/components/ImageSelectionGrid.tsx +32 -189
- package/src/features/image-to-video/presentation/components/ImageSelectionGrid.types.ts +18 -0
- package/src/features/image-to-video/presentation/hooks/useGenerationExecution.ts +142 -0
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.constants.ts +15 -0
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +26 -178
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.types.ts +27 -0
- package/src/features/image-to-video/presentation/hooks/useImageToVideoValidation.ts +46 -0
- package/src/infrastructure/utils/url-extractor/base-extractor.ts +72 -0
- package/src/infrastructure/utils/url-extractor/index.ts +22 -0
- package/src/infrastructure/utils/url-extractor/media-extractors.ts +78 -0
- package/src/infrastructure/utils/url-extractor/multi-extractor.ts +61 -0
- package/src/infrastructure/utils/url-extractor/thumbnail-extractor.ts +31 -0
- package/src/infrastructure/utils/url-extractor.util.ts +8 -218
- package/src/presentation/components/GenerationProgressContent.styles.ts +68 -0
- package/src/presentation/components/GenerationProgressContent.tsx +28 -160
- package/src/presentation/components/GenerationProgressContent.types.ts +23 -0
- package/src/presentation/components/PhotoUploadCard/ImageContent.tsx +48 -0
- package/src/presentation/components/PhotoUploadCard/PhotoUploadCard.styles.ts +112 -0
- package/src/presentation/components/PhotoUploadCard/PhotoUploadCard.tsx +37 -193
- package/src/presentation/components/PhotoUploadCard/PhotoUploadCard.types.ts +42 -0
- package/src/presentation/components/PhotoUploadCard/PlaceholderContent.tsx +45 -0
- package/src/presentation/components/PhotoUploadCard/ValidatingContent.tsx +32 -0
- package/src/presentation/components/PhotoUploadCard/useBorderColor.ts +31 -0
- package/src/presentation/components/ProgressCloseButton.tsx +27 -0
- package/src/presentation/components/ProgressDismissButton.tsx +48 -0
- package/src/presentation/components/ProgressHeader.tsx +64 -0
- package/src/presentation/components/ProgressHint.tsx +62 -0
- package/src/presentation/components/result/ActionButton.tsx +64 -0
- package/src/presentation/components/result/ResultActions.styles.ts +54 -0
- package/src/presentation/components/result/ResultActions.tsx +44 -179
- package/src/presentation/components/result/ResultActions.types.ts +20 -0
- package/src/presentation/components/result/RetryButton.tsx +39 -0
- package/src/presentation/components/result/button-style.utils.ts +56 -0
package/package.json
CHANGED
|
@@ -4,70 +4,21 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React, { useMemo, useCallback } from "react";
|
|
7
|
-
import { View, StyleSheet, TouchableOpacity
|
|
7
|
+
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
|
8
8
|
import {
|
|
9
9
|
AtomicText,
|
|
10
10
|
useAppDesignTokens,
|
|
11
11
|
} from "@umituz/react-native-design-system";
|
|
12
12
|
import { CreationPreview } from "./CreationPreview";
|
|
13
13
|
import { CreationBadges } from "./CreationBadges";
|
|
14
|
-
import { CreationActions
|
|
15
|
-
import
|
|
16
|
-
import
|
|
14
|
+
import { CreationActions } from "./CreationActions";
|
|
15
|
+
import { CreationCardMeta } from "./CreationCardMeta";
|
|
16
|
+
import { useCreationCardActions } from "./useCreationCardActions";
|
|
17
|
+
import { useCreationDateFormatter } from "./CreationCard.utils";
|
|
18
|
+
import type { CreationCardProps } from "./CreationCard.types";
|
|
19
|
+
import type { CreationTypeId } from "../../domain/types";
|
|
17
20
|
import { getPreviewUrl, getCreationTitle } from "../../domain/utils";
|
|
18
21
|
|
|
19
|
-
/**
|
|
20
|
-
* Creation data interface for the card
|
|
21
|
-
* Flexible to support both package and app Creation types
|
|
22
|
-
*/
|
|
23
|
-
export interface CreationCardData {
|
|
24
|
-
id: string;
|
|
25
|
-
type: CreationTypeId | string;
|
|
26
|
-
status?: CreationStatus;
|
|
27
|
-
prompt?: string;
|
|
28
|
-
/** Output object for app-style creations */
|
|
29
|
-
output?: CreationOutput;
|
|
30
|
-
/** URI for package-style creations */
|
|
31
|
-
uri?: string;
|
|
32
|
-
provider?: string;
|
|
33
|
-
createdAt: Date | number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Action callbacks interface
|
|
38
|
-
*/
|
|
39
|
-
export interface CreationCardCallbacks {
|
|
40
|
-
onPress?: (creation: CreationCardData) => void;
|
|
41
|
-
onDownload?: (creation: CreationCardData) => Promise<void>;
|
|
42
|
-
onShare?: (creation: CreationCardData) => Promise<void>;
|
|
43
|
-
onDelete?: (creation: CreationCardData) => void;
|
|
44
|
-
onFavorite?: (creation: CreationCardData) => void;
|
|
45
|
-
onPostToFeed?: (creation: CreationCardData) => void;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
interface CreationCardProps {
|
|
49
|
-
/** Creation data */
|
|
50
|
-
readonly creation: CreationCardData;
|
|
51
|
-
/** Action callbacks */
|
|
52
|
-
readonly callbacks?: CreationCardCallbacks;
|
|
53
|
-
/** Show badges overlay */
|
|
54
|
-
readonly showBadges?: boolean;
|
|
55
|
-
/** Show action buttons */
|
|
56
|
-
readonly showActions?: boolean;
|
|
57
|
-
/** Custom status text (for i18n) */
|
|
58
|
-
readonly statusText?: string;
|
|
59
|
-
/** Custom type text (for i18n) */
|
|
60
|
-
readonly typeText?: string;
|
|
61
|
-
/** Date formatter function */
|
|
62
|
-
readonly formatDate?: (date: Date) => string;
|
|
63
|
-
/** Is sharing in progress */
|
|
64
|
-
readonly isSharing?: boolean;
|
|
65
|
-
/** Is download available */
|
|
66
|
-
readonly isDownloadAvailable?: boolean;
|
|
67
|
-
/** Can post to feed */
|
|
68
|
-
readonly canPostToFeed?: boolean;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
22
|
export function CreationCard({
|
|
72
23
|
creation,
|
|
73
24
|
callbacks = {},
|
|
@@ -81,77 +32,17 @@ export function CreationCard({
|
|
|
81
32
|
canPostToFeed = false,
|
|
82
33
|
}: CreationCardProps) {
|
|
83
34
|
const tokens = useAppDesignTokens();
|
|
84
|
-
|
|
85
|
-
// Prefer getPreviewUrl (which returns thumbnailUrl first) over direct uri
|
|
35
|
+
|
|
86
36
|
const previewUrl = getPreviewUrl(creation.output) || creation.uri;
|
|
87
37
|
const title = getCreationTitle(creation.prompt, creation.type as CreationTypeId);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return formatDate(date);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return date.toLocaleDateString(undefined, {
|
|
100
|
-
month: "short",
|
|
101
|
-
day: "numeric",
|
|
102
|
-
year: "numeric",
|
|
103
|
-
});
|
|
104
|
-
}, [creation.createdAt, formatDate]);
|
|
105
|
-
|
|
106
|
-
// Build actions array
|
|
107
|
-
const actions = useMemo<CreationAction[]>(() => {
|
|
108
|
-
const result: CreationAction[] = [];
|
|
109
|
-
|
|
110
|
-
if (callbacks.onDownload && isDownloadAvailable && creation.output) {
|
|
111
|
-
result.push({
|
|
112
|
-
id: "download",
|
|
113
|
-
icon: "Download",
|
|
114
|
-
onPress: () => callbacks.onDownload?.(creation),
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (callbacks.onShare) {
|
|
119
|
-
result.push({
|
|
120
|
-
id: "share",
|
|
121
|
-
icon: "share-social",
|
|
122
|
-
loading: isSharing,
|
|
123
|
-
onPress: () => callbacks.onShare?.(creation),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (callbacks.onFavorite) {
|
|
128
|
-
result.push({
|
|
129
|
-
id: "favorite",
|
|
130
|
-
icon: "heart-outline",
|
|
131
|
-
onPress: () => callbacks.onFavorite?.(creation),
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (callbacks.onDelete) {
|
|
136
|
-
result.push({
|
|
137
|
-
id: "delete",
|
|
138
|
-
icon: "trash",
|
|
139
|
-
color: "error",
|
|
140
|
-
onPress: () => callbacks.onDelete?.(creation),
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (callbacks.onPostToFeed && canPostToFeed) {
|
|
145
|
-
result.push({
|
|
146
|
-
id: "post",
|
|
147
|
-
icon: "Send",
|
|
148
|
-
filled: true,
|
|
149
|
-
onPress: () => callbacks.onPostToFeed?.(creation),
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return result;
|
|
154
|
-
}, [callbacks, creation, isSharing, isDownloadAvailable, canPostToFeed]);
|
|
38
|
+
const formattedDate = useCreationDateFormatter(creation.createdAt, formatDate);
|
|
39
|
+
const actions = useCreationCardActions({
|
|
40
|
+
callbacks,
|
|
41
|
+
creation,
|
|
42
|
+
isSharing,
|
|
43
|
+
isDownloadAvailable,
|
|
44
|
+
canPostToFeed,
|
|
45
|
+
});
|
|
155
46
|
|
|
156
47
|
const handlePress = useCallback(() => {
|
|
157
48
|
callbacks.onPress?.(creation);
|
|
@@ -185,17 +76,6 @@ export function CreationCard({
|
|
|
185
76
|
title: {
|
|
186
77
|
fontWeight: "600",
|
|
187
78
|
},
|
|
188
|
-
meta: {
|
|
189
|
-
flexDirection: "row",
|
|
190
|
-
alignItems: "center",
|
|
191
|
-
},
|
|
192
|
-
metaText: {
|
|
193
|
-
fontSize: 12,
|
|
194
|
-
color: tokens.colors.textSecondary,
|
|
195
|
-
},
|
|
196
|
-
metaDot: {
|
|
197
|
-
marginHorizontal: 4,
|
|
198
|
-
},
|
|
199
79
|
}),
|
|
200
80
|
[tokens]
|
|
201
81
|
);
|
|
@@ -236,16 +116,10 @@ export function CreationCard({
|
|
|
236
116
|
)}
|
|
237
117
|
</View>
|
|
238
118
|
|
|
239
|
-
<
|
|
240
|
-
<Text style={styles.metaText}>{formattedDate}</Text>
|
|
241
|
-
{creation.provider && (
|
|
242
|
-
<>
|
|
243
|
-
<Text style={[styles.metaText, styles.metaDot]}>•</Text>
|
|
244
|
-
<Text style={styles.metaText}>{creation.provider}</Text>
|
|
245
|
-
</>
|
|
246
|
-
)}
|
|
247
|
-
</View>
|
|
119
|
+
<CreationCardMeta formattedDate={formattedDate} provider={creation.provider} />
|
|
248
120
|
</View>
|
|
249
121
|
</TouchableOpacity>
|
|
250
122
|
);
|
|
251
123
|
}
|
|
124
|
+
|
|
125
|
+
export type { CreationCardProps, CreationCardData, CreationCardCallbacks } from "./CreationCard.types";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreationCard Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { CreationStatus, CreationTypeId } from "../../domain/types";
|
|
6
|
+
import type { CreationOutput } from "../../domain/utils";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creation data interface for the card
|
|
10
|
+
* Flexible to support both package and app Creation types
|
|
11
|
+
*/
|
|
12
|
+
export interface CreationCardData {
|
|
13
|
+
id: string;
|
|
14
|
+
type: CreationTypeId | string;
|
|
15
|
+
status?: CreationStatus;
|
|
16
|
+
prompt?: string;
|
|
17
|
+
/** Output object for app-style creations */
|
|
18
|
+
output?: CreationOutput;
|
|
19
|
+
/** URI for package-style creations */
|
|
20
|
+
uri?: string;
|
|
21
|
+
provider?: string;
|
|
22
|
+
createdAt: Date | number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Action callbacks interface
|
|
27
|
+
*/
|
|
28
|
+
export interface CreationCardCallbacks {
|
|
29
|
+
onPress?: (creation: CreationCardData) => void;
|
|
30
|
+
onDownload?: (creation: CreationCardData) => Promise<void>;
|
|
31
|
+
onShare?: (creation: CreationCardData) => Promise<void>;
|
|
32
|
+
onDelete?: (creation: CreationCardData) => void;
|
|
33
|
+
onFavorite?: (creation: CreationCardData) => void;
|
|
34
|
+
onPostToFeed?: (creation: CreationCardData) => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface CreationCardProps {
|
|
38
|
+
/** Creation data */
|
|
39
|
+
readonly creation: CreationCardData;
|
|
40
|
+
/** Action callbacks */
|
|
41
|
+
readonly callbacks?: CreationCardCallbacks;
|
|
42
|
+
/** Show badges overlay */
|
|
43
|
+
readonly showBadges?: boolean;
|
|
44
|
+
/** Show action buttons */
|
|
45
|
+
readonly showActions?: boolean;
|
|
46
|
+
/** Custom status text (for i18n) */
|
|
47
|
+
readonly statusText?: string;
|
|
48
|
+
/** Custom type text (for i18n) */
|
|
49
|
+
readonly typeText?: string;
|
|
50
|
+
/** Date formatter function */
|
|
51
|
+
readonly formatDate?: (date: Date) => string;
|
|
52
|
+
/** Is sharing in progress */
|
|
53
|
+
readonly isSharing?: boolean;
|
|
54
|
+
/** Is download available */
|
|
55
|
+
readonly isDownloadAvailable?: boolean;
|
|
56
|
+
/** Can post to feed */
|
|
57
|
+
readonly canPostToFeed?: boolean;
|
|
58
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreationCard Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useMemo } from "react";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Format creation date for display
|
|
9
|
+
*/
|
|
10
|
+
export function useCreationDateFormatter(
|
|
11
|
+
createdAt: Date | number,
|
|
12
|
+
formatDate?: (date: Date) => string
|
|
13
|
+
): string {
|
|
14
|
+
return useMemo(() => {
|
|
15
|
+
const date = createdAt instanceof Date
|
|
16
|
+
? createdAt
|
|
17
|
+
: new Date(createdAt);
|
|
18
|
+
|
|
19
|
+
if (formatDate) {
|
|
20
|
+
return formatDate(date);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return date.toLocaleDateString(undefined, {
|
|
24
|
+
month: "short",
|
|
25
|
+
day: "numeric",
|
|
26
|
+
year: "numeric",
|
|
27
|
+
});
|
|
28
|
+
}, [createdAt, formatDate]);
|
|
29
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreationCardMeta Component
|
|
3
|
+
* Displays metadata (date, provider) for CreationCard
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useMemo } from "react";
|
|
7
|
+
import { View, StyleSheet, Text } from "react-native";
|
|
8
|
+
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
9
|
+
|
|
10
|
+
interface CreationCardMetaProps {
|
|
11
|
+
readonly formattedDate: string;
|
|
12
|
+
readonly provider?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function CreationCardMeta({
|
|
16
|
+
formattedDate,
|
|
17
|
+
provider,
|
|
18
|
+
}: CreationCardMetaProps) {
|
|
19
|
+
const tokens = useAppDesignTokens();
|
|
20
|
+
|
|
21
|
+
const styles = useMemo(
|
|
22
|
+
() =>
|
|
23
|
+
StyleSheet.create({
|
|
24
|
+
meta: {
|
|
25
|
+
flexDirection: "row",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
},
|
|
28
|
+
metaText: {
|
|
29
|
+
fontSize: 12,
|
|
30
|
+
color: tokens.colors.textSecondary,
|
|
31
|
+
},
|
|
32
|
+
metaDot: {
|
|
33
|
+
marginHorizontal: 4,
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
[tokens]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<View style={styles.meta}>
|
|
41
|
+
<Text style={styles.metaText}>{formattedDate}</Text>
|
|
42
|
+
{provider && (
|
|
43
|
+
<>
|
|
44
|
+
<Text style={[styles.metaText, styles.metaDot]}>•</Text>
|
|
45
|
+
<Text style={styles.metaText}>{provider}</Text>
|
|
46
|
+
</>
|
|
47
|
+
)}
|
|
48
|
+
</View>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreationsFilterBar Helper Functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
FilterButton,
|
|
7
|
+
MediaFilterLabels,
|
|
8
|
+
StatusFilterLabels,
|
|
9
|
+
} from "./CreationsFilterBar.types";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Helper to create filter buttons from filter state
|
|
13
|
+
*/
|
|
14
|
+
export function createMediaFilterButtons(
|
|
15
|
+
activeFilter: string,
|
|
16
|
+
onSelect: (filter: string) => void,
|
|
17
|
+
labels: MediaFilterLabels
|
|
18
|
+
): FilterButton[] {
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
id: "all",
|
|
22
|
+
label: labels.all,
|
|
23
|
+
icon: "grid",
|
|
24
|
+
active: activeFilter === "all",
|
|
25
|
+
onPress: () => onSelect("all"),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "image",
|
|
29
|
+
label: labels.images,
|
|
30
|
+
icon: "image",
|
|
31
|
+
active: activeFilter === "image",
|
|
32
|
+
onPress: () => onSelect("image"),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "video",
|
|
36
|
+
label: labels.videos,
|
|
37
|
+
icon: "film",
|
|
38
|
+
active: activeFilter === "video",
|
|
39
|
+
onPress: () => onSelect("video"),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "voice",
|
|
43
|
+
label: labels.voice,
|
|
44
|
+
icon: "mic",
|
|
45
|
+
active: activeFilter === "voice",
|
|
46
|
+
onPress: () => onSelect("voice"),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Helper to create status filter buttons
|
|
53
|
+
*/
|
|
54
|
+
export function createStatusFilterButtons(
|
|
55
|
+
activeFilter: string,
|
|
56
|
+
onSelect: (filter: string) => void,
|
|
57
|
+
labels: StatusFilterLabels
|
|
58
|
+
): FilterButton[] {
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
id: "all",
|
|
62
|
+
label: labels.all,
|
|
63
|
+
icon: "options",
|
|
64
|
+
active: activeFilter === "all",
|
|
65
|
+
onPress: () => onSelect("all"),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "completed",
|
|
69
|
+
label: labels.completed,
|
|
70
|
+
icon: "checkmark-circle",
|
|
71
|
+
active: activeFilter === "completed",
|
|
72
|
+
onPress: () => onSelect("completed"),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "processing",
|
|
76
|
+
label: labels.processing,
|
|
77
|
+
icon: "refresh",
|
|
78
|
+
active: activeFilter === "processing",
|
|
79
|
+
onPress: () => onSelect("processing"),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "pending",
|
|
83
|
+
label: labels.pending,
|
|
84
|
+
icon: "time",
|
|
85
|
+
active: activeFilter === "pending",
|
|
86
|
+
onPress: () => onSelect("pending"),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "failed",
|
|
90
|
+
label: labels.failed,
|
|
91
|
+
icon: "close-circle",
|
|
92
|
+
active: activeFilter === "failed",
|
|
93
|
+
onPress: () => onSelect("failed"),
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
}
|
|
@@ -10,35 +10,7 @@ import {
|
|
|
10
10
|
AtomicText,
|
|
11
11
|
AtomicIcon,
|
|
12
12
|
} from "@umituz/react-native-design-system";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Filter button configuration
|
|
16
|
-
*/
|
|
17
|
-
export interface FilterButton {
|
|
18
|
-
/** Unique filter identifier */
|
|
19
|
-
id: string;
|
|
20
|
-
/** Display label */
|
|
21
|
-
label: string;
|
|
22
|
-
/** Icon name */
|
|
23
|
-
icon?: string;
|
|
24
|
-
/** Is this filter active */
|
|
25
|
-
active: boolean;
|
|
26
|
-
/** Handler when pressed */
|
|
27
|
-
onPress: () => void;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface CreationsFilterBarProps {
|
|
31
|
-
/** Array of filter buttons */
|
|
32
|
-
readonly filters: FilterButton[];
|
|
33
|
-
/** Show clear button when any filter is active */
|
|
34
|
-
readonly showClearButton?: boolean;
|
|
35
|
-
/** Clear button label */
|
|
36
|
-
readonly clearLabel?: string;
|
|
37
|
-
/** Clear all filters handler */
|
|
38
|
-
readonly onClear?: () => void;
|
|
39
|
-
/** Has any active filters (for showing clear button) */
|
|
40
|
-
readonly hasActiveFilters?: boolean;
|
|
41
|
-
}
|
|
13
|
+
import type { CreationsFilterBarProps } from "./CreationsFilterBar.types";
|
|
42
14
|
|
|
43
15
|
export function CreationsFilterBar({
|
|
44
16
|
filters,
|
|
@@ -160,95 +132,8 @@ export function CreationsFilterBar({
|
|
|
160
132
|
);
|
|
161
133
|
}
|
|
162
134
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
onSelect: (filter: string) => void,
|
|
169
|
-
labels: { all: string; images: string; videos: string; voice: string }
|
|
170
|
-
): FilterButton[] {
|
|
171
|
-
return [
|
|
172
|
-
{
|
|
173
|
-
id: "all",
|
|
174
|
-
label: labels.all,
|
|
175
|
-
icon: "grid",
|
|
176
|
-
active: activeFilter === "all",
|
|
177
|
-
onPress: () => onSelect("all"),
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
id: "image",
|
|
181
|
-
label: labels.images,
|
|
182
|
-
icon: "image",
|
|
183
|
-
active: activeFilter === "image",
|
|
184
|
-
onPress: () => onSelect("image"),
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
id: "video",
|
|
188
|
-
label: labels.videos,
|
|
189
|
-
icon: "film",
|
|
190
|
-
active: activeFilter === "video",
|
|
191
|
-
onPress: () => onSelect("video"),
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
id: "voice",
|
|
195
|
-
label: labels.voice,
|
|
196
|
-
icon: "mic",
|
|
197
|
-
active: activeFilter === "voice",
|
|
198
|
-
onPress: () => onSelect("voice"),
|
|
199
|
-
},
|
|
200
|
-
];
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Helper to create status filter buttons
|
|
205
|
-
*/
|
|
206
|
-
export function createStatusFilterButtons(
|
|
207
|
-
activeFilter: string,
|
|
208
|
-
onSelect: (filter: string) => void,
|
|
209
|
-
labels: {
|
|
210
|
-
all: string;
|
|
211
|
-
completed: string;
|
|
212
|
-
pending: string;
|
|
213
|
-
processing: string;
|
|
214
|
-
failed: string;
|
|
215
|
-
}
|
|
216
|
-
): FilterButton[] {
|
|
217
|
-
return [
|
|
218
|
-
{
|
|
219
|
-
id: "all",
|
|
220
|
-
label: labels.all,
|
|
221
|
-
icon: "options",
|
|
222
|
-
active: activeFilter === "all",
|
|
223
|
-
onPress: () => onSelect("all"),
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
id: "completed",
|
|
227
|
-
label: labels.completed,
|
|
228
|
-
icon: "checkmark-circle",
|
|
229
|
-
active: activeFilter === "completed",
|
|
230
|
-
onPress: () => onSelect("completed"),
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
id: "processing",
|
|
234
|
-
label: labels.processing,
|
|
235
|
-
icon: "refresh",
|
|
236
|
-
active: activeFilter === "processing",
|
|
237
|
-
onPress: () => onSelect("processing"),
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
id: "pending",
|
|
241
|
-
label: labels.pending,
|
|
242
|
-
icon: "time",
|
|
243
|
-
active: activeFilter === "pending",
|
|
244
|
-
onPress: () => onSelect("pending"),
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
id: "failed",
|
|
248
|
-
label: labels.failed,
|
|
249
|
-
icon: "close-circle",
|
|
250
|
-
active: activeFilter === "failed",
|
|
251
|
-
onPress: () => onSelect("failed"),
|
|
252
|
-
},
|
|
253
|
-
];
|
|
254
|
-
}
|
|
135
|
+
export type { FilterButton, CreationsFilterBarProps } from "./CreationsFilterBar.types";
|
|
136
|
+
export {
|
|
137
|
+
createMediaFilterButtons,
|
|
138
|
+
createStatusFilterButtons,
|
|
139
|
+
} from "./CreationsFilterBar.helpers";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreationsFilterBar Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Filter button configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface FilterButton {
|
|
9
|
+
/** Unique filter identifier */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Display label */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Icon name */
|
|
14
|
+
icon?: string;
|
|
15
|
+
/** Is this filter active */
|
|
16
|
+
active: boolean;
|
|
17
|
+
/** Handler when pressed */
|
|
18
|
+
onPress: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface CreationsFilterBarProps {
|
|
22
|
+
/** Array of filter buttons */
|
|
23
|
+
readonly filters: FilterButton[];
|
|
24
|
+
/** Show clear button when any filter is active */
|
|
25
|
+
readonly showClearButton?: boolean;
|
|
26
|
+
/** Clear button label */
|
|
27
|
+
readonly clearLabel?: string;
|
|
28
|
+
/** Clear all filters handler */
|
|
29
|
+
readonly onClear?: () => void;
|
|
30
|
+
/** Has any active filters (for showing clear button) */
|
|
31
|
+
readonly hasActiveFilters?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface MediaFilterLabels {
|
|
35
|
+
all: string;
|
|
36
|
+
images: string;
|
|
37
|
+
videos: string;
|
|
38
|
+
voice: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface StatusFilterLabels {
|
|
42
|
+
all: string;
|
|
43
|
+
completed: string;
|
|
44
|
+
pending: string;
|
|
45
|
+
processing: string;
|
|
46
|
+
failed: string;
|
|
47
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useCreationCardActions Hook
|
|
3
|
+
* Builds actions array for CreationCard based on callbacks and state
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useMemo } from "react";
|
|
7
|
+
import type { CreationCardData, CreationCardCallbacks } from "./CreationCard.types";
|
|
8
|
+
import type { CreationAction } from "./CreationActions";
|
|
9
|
+
|
|
10
|
+
interface UseCreationCardActionsParams {
|
|
11
|
+
callbacks: CreationCardCallbacks;
|
|
12
|
+
creation: CreationCardData;
|
|
13
|
+
isSharing: boolean;
|
|
14
|
+
isDownloadAvailable: boolean;
|
|
15
|
+
canPostToFeed: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function useCreationCardActions({
|
|
19
|
+
callbacks,
|
|
20
|
+
creation,
|
|
21
|
+
isSharing,
|
|
22
|
+
isDownloadAvailable,
|
|
23
|
+
canPostToFeed,
|
|
24
|
+
}: UseCreationCardActionsParams): CreationAction[] {
|
|
25
|
+
return useMemo<CreationAction[]>(() => {
|
|
26
|
+
const result: CreationAction[] = [];
|
|
27
|
+
|
|
28
|
+
if (callbacks.onDownload && isDownloadAvailable && creation.output) {
|
|
29
|
+
result.push({
|
|
30
|
+
id: "download",
|
|
31
|
+
icon: "Download",
|
|
32
|
+
onPress: () => callbacks.onDownload?.(creation),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (callbacks.onShare) {
|
|
37
|
+
result.push({
|
|
38
|
+
id: "share",
|
|
39
|
+
icon: "share-social",
|
|
40
|
+
loading: isSharing,
|
|
41
|
+
onPress: () => callbacks.onShare?.(creation),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (callbacks.onFavorite) {
|
|
46
|
+
result.push({
|
|
47
|
+
id: "favorite",
|
|
48
|
+
icon: "heart-outline",
|
|
49
|
+
onPress: () => callbacks.onFavorite?.(creation),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (callbacks.onDelete) {
|
|
54
|
+
result.push({
|
|
55
|
+
id: "delete",
|
|
56
|
+
icon: "trash",
|
|
57
|
+
color: "error",
|
|
58
|
+
onPress: () => callbacks.onDelete?.(creation),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (callbacks.onPostToFeed && canPostToFeed) {
|
|
63
|
+
result.push({
|
|
64
|
+
id: "post",
|
|
65
|
+
icon: "Send",
|
|
66
|
+
filled: true,
|
|
67
|
+
onPress: () => callbacks.onPostToFeed?.(creation),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return result;
|
|
72
|
+
}, [callbacks, creation, isSharing, isDownloadAvailable, canPostToFeed]);
|
|
73
|
+
}
|