@umituz/react-native-ai-generation-content 1.12.32 → 1.12.34
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 +3 -1
- package/src/domains/creations/domain/entities/Creation.ts +3 -0
- package/src/domains/creations/domain/repositories/ICreationsRepository.ts +5 -0
- package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +16 -0
- package/src/domains/creations/presentation/components/CreationCard.tsx +24 -10
- package/src/domains/creations/presentation/components/CreationsGrid.tsx +6 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.34",
|
|
4
4
|
"description": "Provider-agnostic AI generation orchestration for React Native",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"@umituz/react-native-firebase": "*",
|
|
46
46
|
"@umituz/react-native-image": "*",
|
|
47
47
|
"@umituz/react-native-offline": "*",
|
|
48
|
+
"@umituz/react-native-timezone": "*",
|
|
48
49
|
"@umituz/react-native-uuid": "*",
|
|
49
50
|
"expo-linear-gradient": ">=15.0.0",
|
|
50
51
|
"firebase": ">=10.0.0",
|
|
@@ -71,6 +72,7 @@
|
|
|
71
72
|
"@umituz/react-native-haptics": "^1.0.2",
|
|
72
73
|
"@umituz/react-native-image": "*",
|
|
73
74
|
"@umituz/react-native-offline": "*",
|
|
75
|
+
"@umituz/react-native-timezone": "^1.3.4",
|
|
74
76
|
"@umituz/react-native-uuid": "*",
|
|
75
77
|
"eslint": "^8.57.0",
|
|
76
78
|
"expo-application": "^7.0.8",
|
|
@@ -12,6 +12,7 @@ export interface Creation {
|
|
|
12
12
|
readonly originalUri?: string;
|
|
13
13
|
readonly createdAt: Date;
|
|
14
14
|
readonly isShared: boolean;
|
|
15
|
+
readonly isFavorite: boolean;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export interface CreationDocument {
|
|
@@ -26,6 +27,7 @@ export interface CreationDocument {
|
|
|
26
27
|
readonly type?: string;
|
|
27
28
|
readonly status?: string;
|
|
28
29
|
readonly isShared: boolean;
|
|
30
|
+
readonly isFavorite?: boolean;
|
|
29
31
|
readonly createdAt: FirebaseTimestamp | Date; // Allow Date for writing
|
|
30
32
|
readonly completedAt?: FirebaseTimestamp | Date;
|
|
31
33
|
}
|
|
@@ -56,5 +58,6 @@ export function mapDocumentToCreation(
|
|
|
56
58
|
originalUri: data.originalImageUrl || data.originalImage,
|
|
57
59
|
createdAt: creationDate,
|
|
58
60
|
isShared: data.isShared ?? false,
|
|
61
|
+
isFavorite: data.isFavorite ?? false,
|
|
59
62
|
};
|
|
60
63
|
}
|
|
@@ -238,4 +238,20 @@ export class CreationsRepository
|
|
|
238
238
|
return false;
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
|
+
|
|
242
|
+
async updateFavorite(
|
|
243
|
+
userId: string,
|
|
244
|
+
creationId: string,
|
|
245
|
+
isFavorite: boolean,
|
|
246
|
+
): Promise<boolean> {
|
|
247
|
+
const docRef = this.getDocRef(userId, creationId);
|
|
248
|
+
if (!docRef) return false;
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
await updateDoc(docRef, { isFavorite });
|
|
252
|
+
return true;
|
|
253
|
+
} catch {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
241
257
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CreationCard Component
|
|
3
|
-
* Displays a creation item with actions
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import React, { useMemo, useCallback } from "react";
|
|
7
2
|
import { View, Image, TouchableOpacity, StyleSheet } from "react-native";
|
|
8
3
|
import {
|
|
@@ -10,6 +5,7 @@ import {
|
|
|
10
5
|
AtomicIcon,
|
|
11
6
|
useAppDesignTokens,
|
|
12
7
|
} from "@umituz/react-native-design-system";
|
|
8
|
+
import { timezoneService } from "@umituz/react-native-timezone";
|
|
13
9
|
import type { Creation } from "../../domain/entities/Creation";
|
|
14
10
|
import type { CreationType } from "../../domain/value-objects/CreationsConfig";
|
|
15
11
|
|
|
@@ -19,6 +15,8 @@ interface CreationCardProps {
|
|
|
19
15
|
readonly onView?: (creation: Creation) => void;
|
|
20
16
|
readonly onShare: (creation: Creation) => void;
|
|
21
17
|
readonly onDelete: (creation: Creation) => void;
|
|
18
|
+
readonly onFavorite?: (creation: Creation, isFavorite: boolean) => void;
|
|
19
|
+
readonly locale?: string;
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
export function CreationCard({
|
|
@@ -27,11 +25,13 @@ export function CreationCard({
|
|
|
27
25
|
onView,
|
|
28
26
|
onShare,
|
|
29
27
|
onDelete,
|
|
28
|
+
onFavorite,
|
|
29
|
+
locale = "en-US",
|
|
30
30
|
}: CreationCardProps) {
|
|
31
31
|
const tokens = useAppDesignTokens();
|
|
32
32
|
|
|
33
33
|
const typeConfig = types.find((t) => t.id === creation.type);
|
|
34
|
-
const icon = typeConfig?.icon
|
|
34
|
+
const icon = typeConfig?.icon;
|
|
35
35
|
const label = typeConfig?.labelKey || creation.type;
|
|
36
36
|
|
|
37
37
|
const handleView = useCallback(() => onView?.(creation), [creation, onView]);
|
|
@@ -40,19 +40,24 @@ export function CreationCard({
|
|
|
40
40
|
() => onDelete(creation),
|
|
41
41
|
[creation, onDelete],
|
|
42
42
|
);
|
|
43
|
+
const handleFavorite = useCallback(
|
|
44
|
+
() => onFavorite?.(creation, !creation.isFavorite),
|
|
45
|
+
[creation, onFavorite],
|
|
46
|
+
);
|
|
43
47
|
|
|
44
48
|
const formattedDate = useMemo(() => {
|
|
45
49
|
const date =
|
|
46
50
|
creation.createdAt instanceof Date
|
|
47
51
|
? creation.createdAt
|
|
48
52
|
: new Date(creation.createdAt);
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
|
|
54
|
+
return timezoneService.formatDateTime(date, locale, {
|
|
51
55
|
month: "short",
|
|
56
|
+
day: "numeric",
|
|
52
57
|
hour: "2-digit",
|
|
53
58
|
minute: "2-digit",
|
|
54
59
|
});
|
|
55
|
-
}, [creation.createdAt]);
|
|
60
|
+
}, [creation.createdAt, locale]);
|
|
56
61
|
|
|
57
62
|
const styles = useMemo(
|
|
58
63
|
() =>
|
|
@@ -112,7 +117,7 @@ export function CreationCard({
|
|
|
112
117
|
<View style={styles.content}>
|
|
113
118
|
<View>
|
|
114
119
|
<View style={styles.typeRow}>
|
|
115
|
-
<
|
|
120
|
+
<AtomicIcon name={icon} size="sm" color="primary" />
|
|
116
121
|
<AtomicText style={styles.typeText}>{label}</AtomicText>
|
|
117
122
|
</View>
|
|
118
123
|
<AtomicText style={styles.dateText}>{formattedDate}</AtomicText>
|
|
@@ -123,6 +128,15 @@ export function CreationCard({
|
|
|
123
128
|
<AtomicIcon name="eye" size="sm" color="primary" />
|
|
124
129
|
</TouchableOpacity>
|
|
125
130
|
)}
|
|
131
|
+
{onFavorite && (
|
|
132
|
+
<TouchableOpacity style={styles.actionBtn} onPress={handleFavorite}>
|
|
133
|
+
<AtomicIcon
|
|
134
|
+
name={creation.isFavorite ? "heart" : "heart-outline"}
|
|
135
|
+
size="sm"
|
|
136
|
+
color={creation.isFavorite ? "error" : "primary"}
|
|
137
|
+
/>
|
|
138
|
+
</TouchableOpacity>
|
|
139
|
+
)}
|
|
126
140
|
<TouchableOpacity style={styles.actionBtn} onPress={handleShare}>
|
|
127
141
|
<AtomicIcon name="share-social" size="sm" color="primary" />
|
|
128
142
|
</TouchableOpacity>
|
|
@@ -13,6 +13,8 @@ interface CreationsGridProps {
|
|
|
13
13
|
readonly onView: (creation: Creation) => void;
|
|
14
14
|
readonly onShare: (creation: Creation) => void;
|
|
15
15
|
readonly onDelete: (creation: Creation) => void;
|
|
16
|
+
readonly onFavorite?: (creation: Creation, isFavorite: boolean) => void;
|
|
17
|
+
readonly locale?: string;
|
|
16
18
|
readonly contentContainerStyle?: ViewStyle;
|
|
17
19
|
readonly ListEmptyComponent?: React.ReactElement | null;
|
|
18
20
|
readonly ListHeaderComponent?: React.ComponentType<unknown> | React.ReactElement | null;
|
|
@@ -26,6 +28,8 @@ export const CreationsGrid: React.FC<CreationsGridProps> = ({
|
|
|
26
28
|
onView,
|
|
27
29
|
onShare,
|
|
28
30
|
onDelete,
|
|
31
|
+
onFavorite,
|
|
32
|
+
locale,
|
|
29
33
|
contentContainerStyle,
|
|
30
34
|
ListEmptyComponent,
|
|
31
35
|
ListHeaderComponent,
|
|
@@ -40,6 +44,8 @@ export const CreationsGrid: React.FC<CreationsGridProps> = ({
|
|
|
40
44
|
onView={() => onView(item)}
|
|
41
45
|
onShare={() => onShare(item)}
|
|
42
46
|
onDelete={() => onDelete(item)}
|
|
47
|
+
onFavorite={onFavorite ? (creation, isFavorite) => onFavorite(creation, isFavorite) : undefined}
|
|
48
|
+
locale={locale}
|
|
43
49
|
/>
|
|
44
50
|
);
|
|
45
51
|
|
|
@@ -19,6 +19,7 @@ interface CreationsGalleryScreenProps {
|
|
|
19
19
|
readonly repository: ICreationsRepository;
|
|
20
20
|
readonly config: CreationsConfig;
|
|
21
21
|
readonly t: (key: string) => string;
|
|
22
|
+
readonly locale?: string;
|
|
22
23
|
readonly enableEditing?: boolean;
|
|
23
24
|
readonly onImageEdit?: (uri: string, creationId: string) => void | Promise<void>;
|
|
24
25
|
readonly onEmptyAction?: () => void;
|
|
@@ -30,6 +31,7 @@ export function CreationsGalleryScreen({
|
|
|
30
31
|
repository,
|
|
31
32
|
config,
|
|
32
33
|
t,
|
|
34
|
+
locale = "en-US",
|
|
33
35
|
enableEditing = false,
|
|
34
36
|
onImageEdit,
|
|
35
37
|
onEmptyAction,
|
|
@@ -95,6 +97,15 @@ export function CreationsGalleryScreen({
|
|
|
95
97
|
setSelectedCreation(creation);
|
|
96
98
|
}, []);
|
|
97
99
|
|
|
100
|
+
// Handle favorite toggle
|
|
101
|
+
const handleFavorite = useCallback(async (creation: Creation, isFavorite: boolean) => {
|
|
102
|
+
if (!userId) return;
|
|
103
|
+
const success = await repository.updateFavorite(userId, creation.id, isFavorite);
|
|
104
|
+
if (success) {
|
|
105
|
+
void refetch();
|
|
106
|
+
}
|
|
107
|
+
}, [userId, repository, refetch]);
|
|
108
|
+
|
|
98
109
|
const styles = useStyles(tokens);
|
|
99
110
|
|
|
100
111
|
const renderEmptyComponent = useMemo(() => (
|
|
@@ -152,6 +163,8 @@ export function CreationsGalleryScreen({
|
|
|
152
163
|
onView={handleView}
|
|
153
164
|
onShare={handleShare}
|
|
154
165
|
onDelete={handleDelete}
|
|
166
|
+
onFavorite={handleFavorite}
|
|
167
|
+
locale={locale}
|
|
155
168
|
contentContainerStyle={{ paddingBottom: insets.bottom + tokens.spacing.xl }}
|
|
156
169
|
ListEmptyComponent={renderEmptyComponent}
|
|
157
170
|
/>
|