@umituz/react-native-ai-generation-content 1.17.251 → 1.17.254

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 (32) hide show
  1. package/package.json +1 -1
  2. package/src/features/couple-future/infrastructure/coupleFeatureRegistry.ts +1 -1
  3. package/src/features/love-message/domain/constants.ts +162 -0
  4. package/src/features/love-message/domain/types.ts +58 -0
  5. package/src/features/love-message/index.ts +35 -0
  6. package/src/features/love-message/infrastructure/persistence/PartnerProfileRepository.ts +58 -0
  7. package/src/features/love-message/infrastructure/prompts/messagePromptBuilder.ts +109 -0
  8. package/src/features/love-message/infrastructure/services/LoveMessageService.ts +35 -0
  9. package/src/features/love-message/presentation/components/CategoryGrid.tsx +87 -0
  10. package/src/features/love-message/presentation/components/DetailsInput.tsx +74 -0
  11. package/src/features/love-message/presentation/components/ExploreHeader.tsx +67 -0
  12. package/src/features/love-message/presentation/components/FieldInput.tsx +83 -0
  13. package/src/features/love-message/presentation/components/GeneratorHeader.tsx +90 -0
  14. package/src/features/love-message/presentation/components/LoveMessageHeroSection.tsx +114 -0
  15. package/src/features/love-message/presentation/components/MessageListItem.tsx +76 -0
  16. package/src/features/love-message/presentation/components/MessageResult.tsx +105 -0
  17. package/src/features/love-message/presentation/components/PartnerInput.tsx +78 -0
  18. package/src/features/love-message/presentation/components/ProgressDots.tsx +48 -0
  19. package/src/features/love-message/presentation/components/StepDetails.tsx +23 -0
  20. package/src/features/love-message/presentation/components/StepPartner.tsx +116 -0
  21. package/src/features/love-message/presentation/components/StepVibe.tsx +30 -0
  22. package/src/features/love-message/presentation/components/ToneSelector.tsx +99 -0
  23. package/src/features/love-message/presentation/components/TrendingSection.tsx +130 -0
  24. package/src/features/love-message/presentation/components/TypeSelector.tsx +98 -0
  25. package/src/features/love-message/presentation/hooks/useLoveMessageGenerator.ts +111 -0
  26. package/src/features/love-message/presentation/hooks/usePartnerProfile.ts +46 -0
  27. package/src/features/love-message/presentation/navigation/LoveMessageStack.tsx +40 -0
  28. package/src/features/love-message/presentation/screens/LoveMessageExploreScreen.tsx +89 -0
  29. package/src/features/love-message/presentation/screens/LoveMessageGeneratorScreen.tsx +128 -0
  30. package/src/features/love-message/presentation/screens/MessageListScreen.tsx +99 -0
  31. package/src/features/love-message/presentation/screens/PartnerProfileScreen.tsx +100 -0
  32. package/src/index.ts +1 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Love Message Explore Screen
3
+ * Premium entry point for Love Message domain
4
+ */
5
+
6
+ import { FC, useCallback } from "react";
7
+ import { View, ScrollView, StyleSheet, Pressable } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ useAppDesignTokens,
12
+ useSafeAreaInsets,
13
+ } from "@umituz/react-native-design-system";
14
+ import { useLocalization } from "@umituz/react-native-localization";
15
+ import { useNavigation } from "@react-navigation/native";
16
+ import { ExploreHeader } from "../components/ExploreHeader";
17
+ import { HeroSection } from "../components/HeroSection";
18
+ import { CategoryGrid } from "../components/CategoryGrid";
19
+ import { TrendingSection } from "../components/TrendingSection";
20
+
21
+ interface LoveMessageExploreScreenProps {
22
+ onNavigateToGenerator: () => void;
23
+ onNavigateToCategory: (categoryId: string) => void;
24
+ onNavigateToTrending: () => void;
25
+ }
26
+
27
+ export const LoveMessageExploreScreen: FC<LoveMessageExploreScreenProps> = ({
28
+ onNavigateToGenerator,
29
+ onNavigateToCategory,
30
+ onNavigateToTrending,
31
+ }) => {
32
+ const tokens = useAppDesignTokens();
33
+ const { bottom } = useSafeAreaInsets();
34
+ const { t } = useLocalization();
35
+
36
+ return (
37
+ <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
38
+ <ExploreHeader onMagicPress={onNavigateToGenerator} />
39
+
40
+ <ScrollView
41
+ showsVerticalScrollIndicator={false}
42
+ contentContainerStyle={{ paddingBottom: bottom + 100 }}
43
+ >
44
+ <HeroSection />
45
+
46
+ <CategoryGrid
47
+ onCategoryPress={onNavigateToCategory}
48
+ />
49
+
50
+ <TrendingSection
51
+ onViewAll={onNavigateToTrending}
52
+ />
53
+ </ScrollView>
54
+
55
+ {/* Floating Action Button */}
56
+ <View style={[styles.fabContainer, { bottom: bottom + tokens.spacing.lg }]}>
57
+ <Pressable
58
+ onPress={onNavigateToGenerator}
59
+ style={[styles.fab, { backgroundColor: tokens.colors.primary }]}
60
+ >
61
+ <AtomicIcon name="sparkles" color="onPrimary" size="sm" />
62
+ <AtomicText type="labelLarge" color="onPrimary" style={styles.fabText}>
63
+ {t("loveMessage.explore.generateMagic")}
64
+ </AtomicText>
65
+ </Pressable>
66
+ </View>
67
+ </View>
68
+ );
69
+ };
70
+
71
+ const styles = StyleSheet.create({
72
+ container: { flex: 1 },
73
+ fabContainer: {
74
+ position: 'absolute',
75
+ left: 20,
76
+ right: 20,
77
+ alignItems: 'center',
78
+ },
79
+ fab: {
80
+ flexDirection: 'row',
81
+ alignItems: 'center',
82
+ justifyContent: 'center',
83
+ paddingVertical: 18,
84
+ paddingHorizontal: 32,
85
+ borderRadius: 32,
86
+ gap: 12,
87
+ },
88
+ fabText: { fontWeight: 'bold', letterSpacing: 1 },
89
+ });
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Love Message Generator Screen
3
+ * Optimized multi-step wizard flow
4
+ */
5
+
6
+ import { FC, useMemo } from "react";
7
+ import { View, ScrollView, StyleSheet, Animated } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicButton,
11
+ useAppDesignTokens,
12
+ useSafeAreaInsets,
13
+ } from "@umituz/react-native-design-system";
14
+ import { useLocalization } from "@umituz/react-native-localization";
15
+ import { useNavigation } from "@react-navigation/native";
16
+ import { ProgressDots } from "../components/ProgressDots";
17
+ import { MessageResult } from "../components/MessageResult";
18
+ import { GeneratorHeader } from "../components/GeneratorHeader";
19
+ import { StepPartner } from "../components/StepPartner";
20
+ import { StepVibe } from "../components/StepVibe";
21
+ import { StepDetails } from "../components/StepDetails";
22
+ import { useLoveMessageGenerator, GeneratorStep } from "../hooks/useLoveMessageGenerator";
23
+
24
+ interface LoveMessageGeneratorScreenProps {
25
+ onBack: () => void;
26
+ onNavigateToProfile: () => void;
27
+ initialType?: MessageType;
28
+ }
29
+
30
+ export const LoveMessageGeneratorScreen: FC<LoveMessageGeneratorScreenProps> = ({
31
+ onBack,
32
+ onNavigateToProfile,
33
+ initialType,
34
+ }) => {
35
+ const tokens = useAppDesignTokens();
36
+ const { bottom } = useSafeAreaInsets();
37
+ const { t } = useLocalization();
38
+ const gen = useLoveMessageGenerator({ onBack, initialType });
39
+
40
+ const stepTitle = useMemo(() => {
41
+ switch (gen.currentStep) {
42
+ case GeneratorStep.PARTNER: return t("loveMessage.generator.stepPartner");
43
+ case GeneratorStep.VIBE: return t("loveMessage.generator.stepVibe");
44
+ case GeneratorStep.DETAILS: return t("loveMessage.generator.stepDetails");
45
+ case GeneratorStep.RESULT: return t("loveMessage.generator.stepResult");
46
+ default: return "";
47
+ }
48
+ }, [gen.currentStep, t]);
49
+
50
+ return (
51
+ <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
52
+ <GeneratorHeader
53
+ currentStep={gen.currentStep}
54
+ partnerName={gen.partnerName}
55
+ onBack={gen.handleBack}
56
+ onNext={gen.handleNext}
57
+ onGenerate={gen.handleGenerate}
58
+ isGenerating={gen.isGenerating}
59
+ />
60
+
61
+ <ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={{ paddingBottom: bottom + 120 }}>
62
+ <View style={styles.heroSection}>
63
+ <ProgressDots currentStep={gen.currentStep} totalSteps={4} />
64
+ <AtomicText type="headlineLarge" color="textPrimary" style={styles.heroTitle}>
65
+ {stepTitle}
66
+ </AtomicText>
67
+ </View>
68
+
69
+ <View style={styles.formContent}>
70
+ {gen.currentStep === GeneratorStep.PARTNER && (
71
+ <Animated.View>
72
+ <StepPartner
73
+ partnerName={gen.partnerName}
74
+ setPartnerName={gen.setPartnerName}
75
+ useProfile={gen.useProfile}
76
+ setUseProfile={gen.setUseProfile}
77
+ hasProfile={gen.hasProfile}
78
+ onEditProfile={onNavigateToProfile}
79
+ />
80
+ </Animated.View>
81
+ )}
82
+
83
+ {gen.currentStep === GeneratorStep.VIBE && (
84
+ <Animated.View>
85
+ <StepVibe
86
+ selectedType={gen.selectedType}
87
+ setSelectedType={gen.setSelectedType}
88
+ selectedTone={gen.selectedTone}
89
+ setSelectedTone={gen.setSelectedTone}
90
+ />
91
+ </Animated.View>
92
+ )}
93
+
94
+ {gen.currentStep === GeneratorStep.DETAILS && (
95
+ <Animated.View>
96
+ <StepDetails details={gen.details} setDetails={gen.setDetails} />
97
+ </Animated.View>
98
+ )}
99
+
100
+ {gen.currentStep === GeneratorStep.RESULT && (
101
+ <MessageResult message={gen.generatedMessage} />
102
+ )}
103
+ </View>
104
+ </ScrollView>
105
+
106
+ {gen.currentStep === GeneratorStep.RESULT && (
107
+ <View style={[styles.footer, { paddingBottom: bottom + 24 }]}>
108
+ <AtomicButton
109
+ title={t("loveMessage.generator.startOver")}
110
+ onPress={gen.startOver}
111
+ variant="outline"
112
+ fullWidth
113
+ style={styles.actionBtn}
114
+ />
115
+ </View>
116
+ )}
117
+ </View>
118
+ );
119
+ };
120
+
121
+ const styles = StyleSheet.create({
122
+ container: { flex: 1 },
123
+ heroSection: { paddingVertical: 32, alignItems: 'center' },
124
+ heroTitle: { fontWeight: 'bold', textAlign: 'center', marginBottom: 8, paddingHorizontal: 20 },
125
+ formContent: { paddingHorizontal: 20 },
126
+ footer: { position: 'absolute', bottom: 0, left: 0, right: 0, padding: 24, backgroundColor: 'transparent' },
127
+ actionBtn: { height: 60, borderRadius: 30 },
128
+ });
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Message List Screen
3
+ */
4
+
5
+ import { FC, useCallback, useMemo } from "react";
6
+ import { View, ScrollView, StyleSheet, Pressable, Share } from "react-native";
7
+ import {
8
+ AtomicText,
9
+ AtomicIcon,
10
+ useAppDesignTokens,
11
+ useSafeAreaInsets,
12
+ } from "@umituz/react-native-design-system";
13
+ import { useLocalization } from "@umituz/react-native-localization";
14
+ import { useNavigation, useRoute } from "@react-navigation/native";
15
+ import { CATEGORY_TEMPLATES, MESSAGE_TYPES } from "../../domain/constants";
16
+ import { MessageListItem } from "../components/MessageListItem";
17
+
18
+ interface MessageListScreenProps {
19
+ categoryId: string;
20
+ onBack: () => void;
21
+ onNavigateToGenerator: (initialType?: string) => void;
22
+ }
23
+
24
+ export const MessageListScreen: FC<MessageListScreenProps> = ({
25
+ categoryId,
26
+ onBack,
27
+ onNavigateToGenerator,
28
+ }) => {
29
+ const tokens = useAppDesignTokens();
30
+ const { top, bottom } = useSafeAreaInsets();
31
+ const { t } = useLocalization();
32
+
33
+ const messages = useMemo(() => CATEGORY_TEMPLATES[categoryId] || [], [categoryId]);
34
+
35
+ const categoryTitle = useMemo(() => {
36
+ if (categoryId === "trending") return t("loveMessage.explore.trending");
37
+ const config = MESSAGE_TYPES.find(c => c.type === categoryId);
38
+ return config ? t(config.labelKey) : categoryId;
39
+ }, [categoryId, t]);
40
+
41
+ const handleShare = useCallback(async (text: string) => {
42
+ try {
43
+ await Share.share({ message: text });
44
+ } catch { /* Ignore */ }
45
+ }, []);
46
+
47
+ return (
48
+ <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
49
+ <View style={[styles.header, { paddingTop: top + tokens.spacing.md }]}>
50
+ <Pressable onPress={onBack} style={styles.backBtn}>
51
+ <AtomicIcon name="arrow-back" color="textPrimary" size="sm" />
52
+ </Pressable>
53
+ <AtomicText type="headlineSmall" color="textPrimary" style={styles.headerTitle}>
54
+ {categoryTitle}
55
+ </AtomicText>
56
+ <View style={{ width: 44 }} />
57
+ </View>
58
+
59
+ <ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={{ paddingBottom: bottom + 100, paddingHorizontal: 16 }}>
60
+ <View style={styles.headlineContainer}>
61
+ <AtomicText type="headlineMedium" color="textPrimary" style={styles.headline}>
62
+ {`${messages.length} messages`}
63
+ </AtomicText>
64
+ <AtomicText type="bodySmall" color="textTertiary">
65
+ AI-crafted for your special moments
66
+ </AtomicText>
67
+ </View>
68
+
69
+ {messages.map((item) => (
70
+ <MessageListItem key={item.id} item={item} onShare={handleShare} />
71
+ ))}
72
+ </ScrollView>
73
+
74
+ <View style={[styles.fabContainer, { bottom: bottom + tokens.spacing.lg }]}>
75
+ <Pressable
76
+ onPress={() => onNavigateToGenerator(categoryId !== "trending" ? categoryId : undefined)}
77
+ style={[styles.fab, { backgroundColor: tokens.colors.primary }]}
78
+ >
79
+ <AtomicIcon name="sparkles" color="onPrimary" size="sm" />
80
+ <AtomicText type="labelLarge" color="onPrimary" style={styles.fabText}>
81
+ GENERATE MORE
82
+ </AtomicText>
83
+ </Pressable>
84
+ </View>
85
+ </View>
86
+ );
87
+ };
88
+
89
+ const styles = StyleSheet.create({
90
+ container: { flex: 1 },
91
+ header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 8, paddingBottom: 16 },
92
+ backBtn: { padding: 12 },
93
+ headerTitle: { fontWeight: 'bold' },
94
+ headlineContainer: { paddingVertical: 24 },
95
+ headline: { fontWeight: 'bold', marginBottom: 4 },
96
+ fabContainer: { position: "absolute", left: 20, right: 20, alignItems: "center" },
97
+ fab: { flexDirection: "row", alignItems: "center", justifyContent: "center", paddingVertical: 16, paddingHorizontal: 24, borderRadius: 32, gap: 12 },
98
+ fabText: { fontWeight: "bold", letterSpacing: 1 },
99
+ });
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Partner Profile Screen
3
+ * Optimized version with hooks and components
4
+ */
5
+
6
+ import { FC } from "react";
7
+ import { View, ScrollView, StyleSheet } from "react-native";
8
+ import {
9
+ AtomicText,
10
+ AtomicButton,
11
+ useAppDesignTokens,
12
+ useSafeAreaInsets,
13
+ } from "@umituz/react-native-design-system";
14
+ import { useLocalization } from "@umituz/react-native-localization";
15
+ import { LOVE_LANGUAGES } from "../../domain/constants";
16
+ import { usePartnerProfile } from "../hooks/usePartnerProfile";
17
+ import { FieldInput } from "../components/FieldInput";
18
+
19
+ export const PartnerProfileScreen: FC = () => {
20
+ const tokens = useAppDesignTokens();
21
+ const { top, bottom } = useSafeAreaInsets();
22
+ const { t } = useLocalization();
23
+ const p = usePartnerProfile();
24
+
25
+ if (p.isLoading) return null;
26
+
27
+ return (
28
+ <View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
29
+ <View style={[styles.header, { paddingTop: top + tokens.spacing.md }]}>
30
+ <AtomicButton icon="arrow-back" onPress={() => p.navigation.goBack()} variant="text" size="sm" />
31
+ <View style={styles.headerTitle}>
32
+ <AtomicText type="headlineSmall" color="textPrimary" style={styles.headerText}>
33
+ {t("loveMessage.partnerProfile.title")}
34
+ </AtomicText>
35
+ </View>
36
+ </View>
37
+
38
+ <ScrollView
39
+ contentContainerStyle={{ paddingBottom: bottom + tokens.spacing.xl, paddingHorizontal: tokens.spacing.lg }}
40
+ showsVerticalScrollIndicator={false}
41
+ >
42
+ <AtomicText type="bodyMedium" color="textSecondary" style={styles.subtitle}>
43
+ {t("loveMessage.partnerProfile.subtitle")}
44
+ </AtomicText>
45
+
46
+ <FieldInput
47
+ label={t("loveMessage.partnerName")} value={p.profile.name}
48
+ onChange={(text) => p.setProfile((prev) => ({ ...prev, name: text }))}
49
+ placeholder={t("loveMessage.partnerNamePlaceholder")}
50
+ />
51
+
52
+ <View style={styles.field}>
53
+ <AtomicText type="labelLarge" color="textPrimary" style={styles.label}>
54
+ {t("loveMessage.partnerProfile.loveLanguage")}
55
+ </AtomicText>
56
+ <View style={styles.chipContainer}>
57
+ {LOVE_LANGUAGES.map((lang) => (
58
+ <AtomicButton
59
+ key={lang.language} title={t(lang.labelKey)}
60
+ onPress={() => p.setProfile((prev) => ({ ...prev, loveLanguage: lang.language }))}
61
+ variant={p.profile.loveLanguage === lang.language ? "primary" : "outline"}
62
+ size="sm" style={styles.chip}
63
+ />
64
+ ))}
65
+ </View>
66
+ </View>
67
+
68
+ <FieldInput
69
+ label={t("loveMessage.partnerProfile.traits")} value={p.profile.traits}
70
+ onChange={(text) => p.setProfile((prev) => ({ ...prev, traits: text }))}
71
+ placeholder={t("loveMessage.partnerProfile.traitsPlaceholder")}
72
+ />
73
+
74
+ <FieldInput
75
+ label={t("loveMessage.partnerProfile.quirks")} value={p.profile.quirks}
76
+ onChange={(text) => p.setProfile((prev) => ({ ...prev, quirks: text }))}
77
+ placeholder={t("loveMessage.partnerProfile.quirksPlaceholder")} multiline
78
+ />
79
+
80
+ <AtomicButton
81
+ title={t("loveMessage.partnerProfile.save")} onPress={p.handleSave}
82
+ disabled={!p.profile.name.trim()} variant="primary" fullWidth style={styles.saveBtn}
83
+ />
84
+ </ScrollView>
85
+ </View>
86
+ );
87
+ };
88
+
89
+ const styles = StyleSheet.create({
90
+ container: { flex: 1 },
91
+ header: { flexDirection: "row", alignItems: "center", paddingHorizontal: 8, paddingBottom: 24 },
92
+ headerTitle: { flex: 1, marginRight: 40, alignItems: "center" },
93
+ headerText: { fontWeight: "bold" },
94
+ subtitle: { marginBottom: 32 },
95
+ field: { marginBottom: 24 },
96
+ label: { marginBottom: 10, marginLeft: 4 },
97
+ chipContainer: { flexDirection: "row", flexWrap: "wrap", gap: 10 },
98
+ chip: { borderRadius: 20 },
99
+ saveBtn: { height: 56, borderRadius: 16, marginTop: 16 },
100
+ });
package/src/index.ts CHANGED
@@ -151,6 +151,7 @@ export * from "./features/text-to-voice";
151
151
  export * from "./features/hd-touch-up";
152
152
  export * from "./features/meme-generator";
153
153
  export * from "./features/couple-future";
154
+ export * from "./features/love-message";
154
155
  export * from "./infrastructure/orchestration";
155
156
 
156
157
  // Result Preview Domain