@umituz/react-native-ai-generation-content 1.17.282 → 1.17.284

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.17.282",
3
+ "version": "1.17.284",
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",
@@ -15,6 +15,7 @@ import { useDeleteCreation } from "../hooks/useDeleteCreation";
15
15
  import { useGalleryFilters } from "../hooks/useGalleryFilters";
16
16
  import { GalleryHeader, CreationCard, GalleryEmptyStates } from "../components";
17
17
  import { ResultPreviewScreen } from "../../../result-preview/presentation/components/ResultPreviewScreen";
18
+ import { StarRatingPicker } from "../../../result-preview/presentation/components/StarRatingPicker";
18
19
  import { useResultActions } from "../../../result-preview/presentation/hooks/useResultActions";
19
20
  import { MEDIA_FILTER_OPTIONS, STATUS_FILTER_OPTIONS } from "../../domain/types/creation-filter";
20
21
  import { getPreviewUrl } from "../../domain/utils";
@@ -45,6 +46,7 @@ export function CreationsGalleryScreen({
45
46
  const { share } = useSharing();
46
47
  const alert = useAlert();
47
48
  const [selectedCreation, setSelectedCreation] = useState<Creation | null>(null);
49
+ const [showRatingPicker, setShowRatingPicker] = useState(false);
48
50
 
49
51
  const { data: creations, isLoading, refetch } = useCreations({ userId, repository });
50
52
  const deleteMutation = useDeleteCreation({ userId, repository });
@@ -101,13 +103,17 @@ export function CreationsGalleryScreen({
101
103
  setSelectedCreation(null);
102
104
  }, []);
103
105
 
104
- const handleRate = useCallback(() => {
106
+ const handleOpenRatingPicker = useCallback(() => {
107
+ setShowRatingPicker(true);
108
+ }, []);
109
+
110
+ const handleSubmitRating = useCallback((rating: number) => {
105
111
  if (!userId || !selectedCreation) return;
106
112
  void (async () => {
107
- const success = await repository.rate(userId, selectedCreation.id, 5);
113
+ const success = await repository.rate(userId, selectedCreation.id, rating);
108
114
  if (success) {
109
- setSelectedCreation({ ...selectedCreation, rating: 5, ratedAt: new Date() });
110
- alert.show(AlertType.SUCCESS, AlertMode.TOAST, t("rating.thankYouTitle"), t("rating.thankYouMessage"));
115
+ setSelectedCreation({ ...selectedCreation, rating, ratedAt: new Date() });
116
+ alert.show(AlertType.SUCCESS, AlertMode.TOAST, t("result.rateSuccessTitle"), t("result.rateSuccessMessage"));
111
117
  void refetch();
112
118
  }
113
119
  })();
@@ -182,29 +188,39 @@ export function CreationsGalleryScreen({
182
188
  if (selectedCreation && selectedImageUrl) {
183
189
  const hasRating = selectedCreation.rating !== undefined && selectedCreation.rating !== null;
184
190
  return (
185
- <ResultPreviewScreen
186
- imageUrl={selectedImageUrl}
187
- isSaving={isSaving}
188
- isSharing={isSharing}
189
- onDownload={handleDownload}
190
- onShare={handleShare}
191
- onTryAgain={handleTryAgain}
192
- onNavigateBack={handleBack}
193
- onRate={handleRate}
194
- hideLabel
195
- iconOnly
196
- showTryAgain={false}
197
- showRating={!hasRating}
198
- translations={{
199
- title: t(config.translations.title),
200
- yourResult: "",
201
- saveButton: t("result.saveButton"),
202
- saving: t("result.saving"),
203
- shareButton: t("result.shareButton"),
204
- sharing: t("result.sharing"),
205
- tryAnother: "",
206
- }}
207
- />
191
+ <>
192
+ <ResultPreviewScreen
193
+ imageUrl={selectedImageUrl}
194
+ isSaving={isSaving}
195
+ isSharing={isSharing}
196
+ onDownload={handleDownload}
197
+ onShare={handleShare}
198
+ onTryAgain={handleTryAgain}
199
+ onNavigateBack={handleBack}
200
+ onRate={handleOpenRatingPicker}
201
+ hideLabel
202
+ iconOnly
203
+ showTryAgain={false}
204
+ showRating={!hasRating}
205
+ translations={{
206
+ title: t(config.translations.title),
207
+ yourResult: "",
208
+ saveButton: t("result.saveButton"),
209
+ saving: t("result.saving"),
210
+ shareButton: t("result.shareButton"),
211
+ sharing: t("result.sharing"),
212
+ tryAnother: "",
213
+ }}
214
+ />
215
+ <StarRatingPicker
216
+ visible={showRatingPicker}
217
+ onClose={() => setShowRatingPicker(false)}
218
+ onRate={handleSubmitRating}
219
+ title={t("result.rateTitle")}
220
+ submitLabel={t("common.submit")}
221
+ cancelLabel={t("common.cancel")}
222
+ />
223
+ </>
208
224
  );
209
225
  }
210
226
 
@@ -82,7 +82,7 @@ export const ResultActionBar: React.FC<ResultActionBarProps> = ({
82
82
  {isSaving ? (
83
83
  <ActivityIndicator color={tokens.colors.textInverse} size="small" />
84
84
  ) : (
85
- <AtomicIcon name="Download" customSize={24} color="onPrimary" />
85
+ <AtomicIcon name="download-outline" customSize={24} color="onPrimary" />
86
86
  )}
87
87
  </TouchableOpacity>
88
88
  <TouchableOpacity
@@ -94,7 +94,7 @@ export const ResultActionBar: React.FC<ResultActionBarProps> = ({
94
94
  {isSharing ? (
95
95
  <ActivityIndicator color={tokens.colors.textInverse} size="small" />
96
96
  ) : (
97
- <AtomicIcon name="Share2" customSize={24} color="onPrimary" />
97
+ <AtomicIcon name="share-social-outline" customSize={24} color="onPrimary" />
98
98
  )}
99
99
  </TouchableOpacity>
100
100
  {showRating && onRate && (
@@ -103,7 +103,7 @@ export const ResultActionBar: React.FC<ResultActionBarProps> = ({
103
103
  onPress={onRate}
104
104
  activeOpacity={0.7}
105
105
  >
106
- <AtomicIcon name="Star" customSize={24} color="onPrimary" />
106
+ <AtomicIcon name="star-outline" customSize={24} color="onPrimary" />
107
107
  </TouchableOpacity>
108
108
  )}
109
109
  </View>
@@ -0,0 +1,149 @@
1
+ /**
2
+ * StarRatingPicker Component
3
+ * Shows 5 stars for rating selection
4
+ */
5
+
6
+ import React, { useState, useMemo } from "react";
7
+ import { StyleSheet, View, TouchableOpacity, Modal } from "react-native";
8
+ import {
9
+ AtomicIcon,
10
+ AtomicText,
11
+ AtomicButton,
12
+ useAppDesignTokens,
13
+ } from "@umituz/react-native-design-system";
14
+
15
+ export interface StarRatingPickerProps {
16
+ visible: boolean;
17
+ onClose: () => void;
18
+ onRate: (rating: number) => void;
19
+ title?: string;
20
+ submitLabel?: string;
21
+ cancelLabel?: string;
22
+ }
23
+
24
+ export const StarRatingPicker: React.FC<StarRatingPickerProps> = ({
25
+ visible,
26
+ onClose,
27
+ onRate,
28
+ title = "Rate this creation",
29
+ submitLabel = "Submit",
30
+ cancelLabel = "Cancel",
31
+ }) => {
32
+ const tokens = useAppDesignTokens();
33
+ const [selectedRating, setSelectedRating] = useState(0);
34
+
35
+ const styles = useMemo(
36
+ () =>
37
+ StyleSheet.create({
38
+ overlay: {
39
+ flex: 1,
40
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
41
+ justifyContent: "center",
42
+ alignItems: "center",
43
+ padding: tokens.spacing.lg,
44
+ },
45
+ container: {
46
+ backgroundColor: tokens.colors.surface,
47
+ borderRadius: 20,
48
+ padding: tokens.spacing.xl,
49
+ width: "100%",
50
+ maxWidth: 320,
51
+ alignItems: "center",
52
+ },
53
+ title: {
54
+ fontSize: 18,
55
+ fontWeight: "700",
56
+ color: tokens.colors.textPrimary,
57
+ marginBottom: tokens.spacing.lg,
58
+ textAlign: "center",
59
+ },
60
+ starsContainer: {
61
+ flexDirection: "row",
62
+ justifyContent: "center",
63
+ gap: 8,
64
+ marginBottom: tokens.spacing.xl,
65
+ },
66
+ starButton: {
67
+ padding: 4,
68
+ },
69
+ buttonsContainer: {
70
+ flexDirection: "row",
71
+ gap: tokens.spacing.md,
72
+ width: "100%",
73
+ },
74
+ button: {
75
+ flex: 1,
76
+ },
77
+ }),
78
+ [tokens],
79
+ );
80
+
81
+ const handleSubmit = () => {
82
+ if (selectedRating > 0) {
83
+ onRate(selectedRating);
84
+ setSelectedRating(0);
85
+ onClose();
86
+ }
87
+ };
88
+
89
+ const handleClose = () => {
90
+ setSelectedRating(0);
91
+ onClose();
92
+ };
93
+
94
+ return (
95
+ <Modal
96
+ visible={visible}
97
+ transparent
98
+ animationType="fade"
99
+ onRequestClose={handleClose}
100
+ >
101
+ <TouchableOpacity
102
+ style={styles.overlay}
103
+ activeOpacity={1}
104
+ onPress={handleClose}
105
+ >
106
+ <TouchableOpacity
107
+ style={styles.container}
108
+ activeOpacity={1}
109
+ onPress={() => {}}
110
+ >
111
+ <AtomicText style={styles.title}>{title}</AtomicText>
112
+ <View style={styles.starsContainer}>
113
+ {[1, 2, 3, 4, 5].map((star) => (
114
+ <TouchableOpacity
115
+ key={star}
116
+ style={styles.starButton}
117
+ onPress={() => setSelectedRating(star)}
118
+ activeOpacity={0.7}
119
+ >
120
+ <AtomicIcon
121
+ name={star <= selectedRating ? "star" : "star-outline"}
122
+ customSize={40}
123
+ customColor={star <= selectedRating ? "#FFD700" : tokens.colors.textTertiary}
124
+ />
125
+ </TouchableOpacity>
126
+ ))}
127
+ </View>
128
+ <View style={styles.buttonsContainer}>
129
+ <View style={styles.button}>
130
+ <AtomicButton
131
+ title={cancelLabel}
132
+ variant="secondary"
133
+ onPress={handleClose}
134
+ />
135
+ </View>
136
+ <View style={styles.button}>
137
+ <AtomicButton
138
+ title={submitLabel}
139
+ variant="primary"
140
+ onPress={handleSubmit}
141
+ disabled={selectedRating === 0}
142
+ />
143
+ </View>
144
+ </View>
145
+ </TouchableOpacity>
146
+ </TouchableOpacity>
147
+ </Modal>
148
+ );
149
+ };
@@ -7,6 +7,8 @@ export { ResultImageCard } from "./ResultImageCard";
7
7
  export { ResultActionBar } from "./ResultActionBar";
8
8
  export { RecentCreationsSection } from "./RecentCreationsSection";
9
9
  export { GenerationErrorScreen } from "./GenerationErrorScreen";
10
+ export { StarRatingPicker } from "./StarRatingPicker";
11
+ export type { StarRatingPickerProps } from "./StarRatingPicker";
10
12
  export type {
11
13
  GenerationErrorTranslations,
12
14
  GenerationErrorConfig,