@umituz/react-native-settings 4.23.84 → 4.23.85

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 (54) hide show
  1. package/package.json +1 -1
  2. package/src/domains/about/presentation/hooks/useAboutInfo.ts +0 -2
  3. package/src/domains/appearance/presentation/components/ColorPicker.tsx +0 -1
  4. package/src/domains/appearance/presentation/components/ThemeModeSection.tsx +0 -1
  5. package/src/domains/appearance/presentation/components/ThemeOption.tsx +0 -1
  6. package/src/domains/feedback/presentation/components/FeedbackForm.tsx +0 -1
  7. package/src/domains/feedback/presentation/components/FeedbackModal.tsx +12 -12
  8. package/src/domains/feedback/presentation/components/SupportSection.tsx +0 -1
  9. package/src/domains/localization/infrastructure/components/useLanguageSwitcher.ts +0 -1
  10. package/src/domains/localization/infrastructure/hooks/useLanguageSelection.ts +0 -4
  11. package/src/domains/localization/infrastructure/hooks/useTranslation.ts +0 -1
  12. package/src/domains/localization/infrastructure/storage/LanguageInitializer.ts +0 -1
  13. package/src/domains/localization/infrastructure/storage/LanguageSwitcher.ts +0 -4
  14. package/src/domains/localization/infrastructure/storage/LocalizationStore.ts +0 -5
  15. package/src/domains/localization/presentation/components/LanguageItem.tsx +0 -1
  16. package/src/domains/localization/presentation/providers/LocalizationManager.tsx +0 -1
  17. package/src/domains/localization/presentation/screens/LanguageSelectionScreen.tsx +0 -3
  18. package/src/domains/notifications/infrastructure/services/NotificationService.ts +0 -1
  19. package/src/domains/notifications/infrastructure/utils/dev.ts +0 -3
  20. package/src/domains/notifications/quietHours/infrastructure/hooks/useQuietHoursActions.ts +0 -1
  21. package/src/domains/notifications/reminders/infrastructure/hooks/useReminderActions.ts +0 -6
  22. package/src/domains/notifications/reminders/presentation/components/ReminderForm.tsx +0 -5
  23. package/src/domains/rating/application/services/RatingService.ts +13 -63
  24. package/src/domains/rating/infrastructure/storage/RatingStorage.ts +14 -36
  25. package/src/domains/rating/presentation/hooks/useAppRating.tsx +0 -1
  26. package/src/infrastructure/utils/dateUtils.ts +61 -0
  27. package/src/infrastructure/utils/memoComparisonUtils.ts +68 -0
  28. package/src/infrastructure/utils/sanitizers.ts +49 -0
  29. package/src/infrastructure/utils/translationHelpers.ts +81 -0
  30. package/src/infrastructure/utils/validators.ts +59 -0
  31. package/src/presentation/components/SettingsItemCard.tsx +129 -172
  32. package/src/presentation/components/settings/SettingsItemCardContent.tsx +70 -0
  33. package/src/presentation/components/settings/SettingsItemCardRightElement.tsx +42 -0
  34. package/src/presentation/components/settings/SettingsItemCardSection.tsx +29 -0
  35. package/src/presentation/hooks/useSettingsScreenConfig.ts +19 -54
  36. package/src/presentation/navigation/hooks/useSettingsScreens.ts +75 -89
  37. package/src/presentation/screens/components/GamificationSettingsItem.tsx +20 -17
  38. package/src/presentation/screens/components/SettingsContent.tsx +29 -0
  39. package/src/presentation/screens/components/SubscriptionSettingsItem.tsx +13 -4
  40. package/src/presentation/screens/components/VideoTutorialSettingsItem.tsx +47 -0
  41. package/src/presentation/screens/components/WalletSettingsItem.tsx +13 -4
  42. package/src/presentation/screens/components/sections/CustomSettingsList.tsx +12 -5
  43. package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +12 -11
  44. package/src/presentation/screens/components/sections/IdentitySettingsSection.tsx +4 -1
  45. package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +16 -10
  46. package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +9 -4
  47. package/src/presentation/screens/hooks/useFeatureDetection.ts +2 -0
  48. package/src/presentation/screens/types/SettingsConfig.ts +8 -1
  49. package/src/presentation/screens/types/UserFeatureConfig.ts +20 -0
  50. package/src/presentation/screens/types/index.ts +1 -0
  51. package/src/presentation/screens/utils/normalizeConfig.ts +7 -1
  52. package/src/presentation/utils/accountConfigUtils.ts +67 -0
  53. package/src/presentation/utils/screenFactory.ts +87 -0
  54. package/src/presentation/utils/userProfileUtils.ts +51 -0
@@ -2,14 +2,13 @@ import React, { useMemo } from "react";
2
2
  import { SettingsSection } from "../../../components/SettingsSection";
3
3
  import { SettingsItemCard } from "../../../components/SettingsItemCard";
4
4
  import type { CustomSettingsSection } from "../../types";
5
+ import { createSinglePropComparator } from "../../../../infrastructure/utils/memoComparisonUtils";
5
6
 
6
7
  interface CustomSettingsListProps {
7
8
  customSections?: CustomSettingsSection[];
8
9
  }
9
10
 
10
- export const CustomSettingsList: React.FC<CustomSettingsListProps> = ({
11
- customSections = [],
12
- }) => {
11
+ export const CustomSettingsList: React.FC<CustomSettingsListProps> = ({ customSections = [] }) => {
13
12
  const sortedSections = useMemo(() => {
14
13
  return Array.from(customSections)
15
14
  .sort((a: CustomSettingsSection, b: CustomSettingsSection) => (a.order ?? 999) - (b.order ?? 999));
@@ -25,9 +24,9 @@ export const CustomSettingsList: React.FC<CustomSettingsListProps> = ({
25
24
  title={section.title}
26
25
  >
27
26
  {section.content}
28
- {!section.content && section.items && section.items.length > 0 && section.items.map((item) => (
27
+ {!section.content && section.items && section.items.length > 0 && section.items.map((item, itemIndex) => (
29
28
  <SettingsItemCard
30
- key={item.id || `item-${index}`}
29
+ key={item.id || `item-${itemIndex}`}
31
30
  title={item.title}
32
31
  description={item.subtitle}
33
32
  icon={item.icon}
@@ -42,3 +41,11 @@ export const CustomSettingsList: React.FC<CustomSettingsListProps> = ({
42
41
  </>
43
42
  );
44
43
  };
44
+
45
+ CustomSettingsList.displayName = "CustomSettingsList";
46
+
47
+ export const MemoizedCustomSettingsList = React.memo(
48
+ CustomSettingsList,
49
+ createSinglePropComparator("customSections")
50
+ );
51
+ MemoizedCustomSettingsList.displayName = "MemoizedCustomSettingsList";
@@ -5,8 +5,8 @@ import { NotificationsSection } from "../../../../domains/notifications";
5
5
  import { useLocalization, getLanguageByCode } from "../../../../domains/localization";
6
6
  import { SettingsItemCard } from "../../../components/SettingsItemCard";
7
7
  import type { NormalizedConfig } from "../../utils/normalizeConfig";
8
-
9
8
  import { SettingsSection } from "../../../components/SettingsSection";
9
+ import { compareConfigAndFeatures } from "../../../../infrastructure/utils/memoComparisonUtils";
10
10
 
11
11
  interface FeatureSettingsSectionProps {
12
12
  normalizedConfig: NormalizedConfig;
@@ -24,23 +24,22 @@ export const FeatureSettingsSection: React.FC<FeatureSettingsSectionProps> = ({
24
24
  const { t, currentLanguage } = useLocalization();
25
25
  const navigation = useAppNavigation();
26
26
 
27
- const handleLanguagePress = () => {
27
+ const handleLanguagePress = React.useCallback(() => {
28
28
  if (normalizedConfig.language.config?.onPress) {
29
29
  normalizedConfig.language.config.onPress();
30
30
  } else {
31
- const route =
32
- normalizedConfig.language.config?.route || "LanguageSelection";
31
+ const route = normalizedConfig.language.config?.route || "LanguageSelection";
33
32
  navigation.navigate(route as never);
34
33
  }
35
- };
34
+ }, [navigation, normalizedConfig.language.config]);
36
35
 
37
- const currentLanguageData = getLanguageByCode(currentLanguage);
38
- const languageDisplayName = currentLanguageData
39
- ? `${currentLanguageData.flag} ${currentLanguageData.nativeName}`
40
- : currentLanguage;
36
+ const currentLanguageData = React.useMemo(() => getLanguageByCode(currentLanguage), [currentLanguage]);
37
+ const languageDisplayName = React.useMemo(() => {
38
+ if (!currentLanguageData) return currentLanguage;
39
+ return `${currentLanguageData.flag} ${currentLanguageData.nativeName}`;
40
+ }, [currentLanguageData, currentLanguage]);
41
41
 
42
- if (!features.appearance && !features.language && !features.notifications)
43
- return null;
42
+ if (!features.appearance && !features.language && !features.notifications) return null;
44
43
 
45
44
  return (
46
45
  <SettingsSection
@@ -85,3 +84,5 @@ export const FeatureSettingsSection: React.FC<FeatureSettingsSectionProps> = ({
85
84
  );
86
85
  };
87
86
 
87
+ export const MemoizedFeatureSettingsSection = React.memo(FeatureSettingsSection, compareConfigAndFeatures);
88
+ MemoizedFeatureSettingsSection.displayName = "MemoizedFeatureSettingsSection";
@@ -3,8 +3,8 @@ import { AboutSection } from "../../../../domains/about/presentation/components/
3
3
  import { LegalSection } from "../../../../domains/legal/presentation/components/LegalSection";
4
4
  import { useLocalization } from "../../../../domains/localization";
5
5
  import type { NormalizedConfig } from "../../utils/normalizeConfig";
6
-
7
6
  import { SettingsSection } from "../../../components/SettingsSection";
7
+ import { compareConfigAndFeatures } from "../../../../infrastructure/utils/memoComparisonUtils";
8
8
 
9
9
  interface IdentitySettingsSectionProps {
10
10
  normalizedConfig: NormalizedConfig;
@@ -48,4 +48,7 @@ export const IdentitySettingsSection: React.FC<IdentitySettingsSectionProps> = (
48
48
  );
49
49
  };
50
50
 
51
+ IdentitySettingsSection.displayName = "IdentitySettingsSection";
51
52
 
53
+ export const MemoizedIdentitySettingsSection = React.memo(IdentitySettingsSection, compareConfigAndFeatures);
54
+ MemoizedIdentitySettingsSection.displayName = "MemoizedIdentitySettingsSection";
@@ -3,6 +3,7 @@ import { View, StyleSheet } from "react-native";
3
3
  import { ProfileSection } from "@umituz/react-native-auth";
4
4
  import { useLocalization } from "../../../../domains/localization";
5
5
  import { useAppNavigation } from "@umituz/react-native-design-system";
6
+ import { createSinglePropComparator } from "../../../../infrastructure/utils/memoComparisonUtils";
6
7
 
7
8
  export interface ProfileSectionLoaderProps {
8
9
  userProfile?: {
@@ -16,24 +17,27 @@ export interface ProfileSectionLoaderProps {
16
17
  };
17
18
  }
18
19
 
19
-
20
- export const ProfileSectionLoader: React.FC<ProfileSectionLoaderProps> = ({ userProfile }) => {
20
+ export const ProfileSectionLoader: React.FC<ProfileSectionLoaderProps> = React.memo(({ userProfile }) => {
21
21
  const { t } = useLocalization();
22
22
  const navigation = useAppNavigation();
23
23
 
24
- if (!userProfile) return null;
25
-
26
- const handlePress = () => {
24
+ const handlePress = React.useCallback(() => {
25
+ if (!userProfile) return;
27
26
  if (userProfile.onPress) {
28
27
  userProfile.onPress();
29
28
  } else if (userProfile.accountSettingsRoute) {
30
29
  navigation.navigate(userProfile.accountSettingsRoute);
31
30
  }
32
- };
31
+ }, [navigation, userProfile]);
33
32
 
34
- const anonymousDisplayName = userProfile.isAnonymous && userProfile.userId
35
- ? `${t("profile.guest", "Guest")} ${userProfile.userId.substring(0, 8)}`
36
- : t("settings.profile.anonymousName", "Anonymous User");
33
+ const anonymousDisplayName = React.useMemo(() => {
34
+ if (!userProfile) return "";
35
+ return userProfile.isAnonymous && userProfile.userId
36
+ ? `${t("profile.guest", "Guest")} ${userProfile.userId.substring(0, 8)}`
37
+ : t("settings.profile.anonymousName", "Anonymous User");
38
+ }, [userProfile, t]);
39
+
40
+ if (!userProfile) return null;
37
41
 
38
42
  return (
39
43
  <View style={styles.profileContainer}>
@@ -53,7 +57,9 @@ export const ProfileSectionLoader: React.FC<ProfileSectionLoaderProps> = ({ user
53
57
  />
54
58
  </View>
55
59
  );
56
- };
60
+ }, createSinglePropComparator("userProfile"));
61
+
62
+ ProfileSectionLoader.displayName = "ProfileSectionLoader";
57
63
 
58
64
  const styles = StyleSheet.create({
59
65
  profileContainer: {
@@ -5,6 +5,7 @@ import { SupportSection } from "../../../../domains/feedback/presentation/compon
5
5
  import { SettingsSection } from "../../../components/SettingsSection";
6
6
  import { SettingsItemCard } from "../../../components/SettingsItemCard";
7
7
  import type { NormalizedConfig } from "../../utils/normalizeConfig";
8
+ import { compareConfigAndFeatures } from "../../../../infrastructure/utils/memoComparisonUtils";
8
9
 
9
10
  interface SupportSettingsSectionProps {
10
11
  features: { feedback: boolean; rating: boolean; faqs: boolean; [key: string]: boolean };
@@ -30,10 +31,10 @@ export const SupportSettingsSection: React.FC<SupportSettingsSectionProps> = ({
30
31
  <SupportSection
31
32
  renderSection={(props: { title: string; children: React.ReactNode }) => <>{props.children}</>}
32
33
  renderItem={(props: { title: string; icon: string; onPress: () => void; isLast?: boolean }) => (
33
- <SettingsItemCard
34
- title={props.title}
35
- icon={props.icon}
36
- onPress={props.onPress}
34
+ <SettingsItemCard
35
+ title={props.title}
36
+ icon={props.icon}
37
+ onPress={props.onPress}
37
38
  noBackground={true}
38
39
  hideMargin={true}
39
40
  />
@@ -98,3 +99,7 @@ export const SupportSettingsSection: React.FC<SupportSettingsSectionProps> = ({
98
99
  );
99
100
  };
100
101
 
102
+ SupportSettingsSection.displayName = "SupportSettingsSection";
103
+
104
+ export const MemoizedSupportSettingsSection = React.memo(SupportSettingsSection, compareConfigAndFeatures);
105
+ MemoizedSupportSettingsSection.displayName = "MemoizedSupportSettingsSection";
@@ -51,6 +51,7 @@ export function useFeatureDetection(
51
51
  subscription,
52
52
  wallet,
53
53
  gamification,
54
+ videoTutorial,
54
55
  } = normalizedConfig;
55
56
 
56
57
  const notificationServiceAvailable = !!options?.notificationServiceAvailable;
@@ -118,6 +119,7 @@ export function useFeatureDetection(
118
119
  subscription: subscription.enabled,
119
120
  wallet: wallet.enabled,
120
121
  gamification: gamification.enabled,
122
+ videoTutorial: videoTutorial.enabled,
121
123
  };
122
124
  }, [normalizedConfig, navigation, options]);
123
125
  }
@@ -21,6 +21,7 @@ import type {
21
21
  SubscriptionConfig,
22
22
  WalletConfig,
23
23
  GamificationItemConfig,
24
+ VideoTutorialConfig,
24
25
  } from "./UserFeatureConfig";
25
26
 
26
27
  /**
@@ -133,10 +134,16 @@ export interface SettingsConfig {
133
134
 
134
135
  /**
135
136
  * Gamification settings configuration
136
- * @default false
137
+ * @default 'auto'
137
138
  */
138
139
  gamification?: FeatureVisibility | GamificationItemConfig;
139
140
 
141
+ /**
142
+ * Video tutorial settings configuration
143
+ * @default 'auto'
144
+ */
145
+ videoTutorial?: FeatureVisibility | VideoTutorialConfig;
146
+
140
147
  /**
141
148
  * Custom empty state text when no settings are available
142
149
  */
@@ -161,3 +161,23 @@ export interface GamificationItemConfig {
161
161
  achievementsCount?: number;
162
162
  }
163
163
 
164
+ /**
165
+ * Video Tutorial Settings Configuration
166
+ */
167
+ export interface VideoTutorialConfig {
168
+ /** Enable video tutorial feature */
169
+ enabled?: FeatureVisibility;
170
+ /** Custom title for the video tutorial section */
171
+ title?: string;
172
+ /** Custom label for the video tutorial item */
173
+ description?: string;
174
+ /** Custom icon name (Ionicons) */
175
+ icon?: string;
176
+ /** Custom section title for grouping */
177
+ sectionTitle?: string;
178
+ /** Handler to open video tutorial screen */
179
+ onPress?: () => void;
180
+ /** Navigation route for video tutorial screen */
181
+ route?: string;
182
+ }
183
+
@@ -21,6 +21,7 @@ export type {
21
21
  SubscriptionConfig,
22
22
  WalletConfig,
23
23
  GamificationItemConfig,
24
+ VideoTutorialConfig,
24
25
  } from "./UserFeatureConfig";
25
26
  export type { GamificationSettingsConfig as GamificationConfig } from "../../../domains/gamification";
26
27
  export type { SettingsConfig } from "./SettingsConfig";
@@ -18,6 +18,7 @@ import type {
18
18
  SubscriptionConfig,
19
19
  WalletConfig,
20
20
  GamificationItemConfig,
21
+ VideoTutorialConfig,
21
22
  SettingsConfig,
22
23
  } from "../types";
23
24
 
@@ -74,6 +75,10 @@ export interface NormalizedConfig {
74
75
  enabled: boolean;
75
76
  config?: GamificationItemConfig;
76
77
  };
78
+ videoTutorial: {
79
+ enabled: boolean;
80
+ config?: VideoTutorialConfig;
81
+ };
77
82
  }
78
83
 
79
84
  /**
@@ -121,6 +126,7 @@ export function normalizeSettingsConfig(
121
126
  faqs: normalizeConfigValue(config?.faqs, false),
122
127
  subscription: normalizeConfigValue(config?.subscription, false),
123
128
  wallet: normalizeConfigValue(config?.wallet, false),
124
- gamification: normalizeConfigValue(config?.gamification, false),
129
+ gamification: normalizeConfigValue(config?.gamification, "auto"),
130
+ videoTutorial: normalizeConfigValue(config?.videoTutorial, "auto"),
125
131
  };
126
132
  }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Account Configuration Utilities
3
+ *
4
+ * Helper functions for creating account screen configurations.
5
+ */
6
+
7
+ import type { AccountScreenConfig } from "@umituz/react-native-auth";
8
+
9
+ export interface CreateAccountConfigParams {
10
+ displayName?: string;
11
+ userId?: string;
12
+ photoURL?: string;
13
+ isAnonymous?: boolean;
14
+ avatarUrl?: string;
15
+ onSignIn: () => void;
16
+ onLogout: () => Promise<void>;
17
+ onDeleteAccount: () => Promise<void>;
18
+ t: (key: string) => string;
19
+ }
20
+
21
+ /**
22
+ * Create account screen configuration
23
+ */
24
+ export function createAccountConfig(params: CreateAccountConfigParams): AccountScreenConfig {
25
+ const {
26
+ displayName,
27
+ userId,
28
+ photoURL,
29
+ isAnonymous,
30
+ avatarUrl,
31
+ onSignIn,
32
+ onLogout,
33
+ onDeleteAccount,
34
+ t,
35
+ } = params;
36
+
37
+ const anonymous = isAnonymous ?? true;
38
+
39
+ return {
40
+ profile: {
41
+ displayName: displayName || t("settings.profile.anonymousName"),
42
+ userId: userId ?? undefined,
43
+ isAnonymous: anonymous,
44
+ avatarUrl: avatarUrl ?? photoURL ?? undefined,
45
+ benefits: anonymous ? [
46
+ t("settings.profile.benefits.saveHistory"),
47
+ t("settings.profile.benefits.syncDevices"),
48
+ t("settings.profile.benefits.cloudSync"),
49
+ t("settings.profile.benefits.secureBackup"),
50
+ ] : undefined,
51
+ },
52
+ isAnonymous: anonymous,
53
+ editProfileText: t("settings.account.editProfile"),
54
+ onSignIn,
55
+ accountActions: {
56
+ onLogout,
57
+ onDeleteAccount,
58
+ logoutText: t("settings.account.logout"),
59
+ logoutConfirmTitle: t("settings.account.logoutConfirmTitle"),
60
+ logoutConfirmMessage: t("settings.account.logoutConfirmMessage"),
61
+ cancelText: t("common.cancel"),
62
+ deleteAccountText: t("settings.account.deleteAccount"),
63
+ deleteConfirmTitle: t("settings.account.deleteConfirmTitle"),
64
+ deleteConfirmMessage: t("settings.account.deleteConfirmMessage"),
65
+ },
66
+ };
67
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Screen Factory Utilities
3
+ *
4
+ * Helper functions for creating stack screen configurations.
5
+ */
6
+
7
+ import React from "react";
8
+ import type { StackScreen } from "@umituz/react-native-design-system";
9
+ import type { AdditionalScreen } from "../navigation/types";
10
+
11
+ /**
12
+ * Create a basic stack screen configuration
13
+ */
14
+ export function createStackScreen(
15
+ name: string,
16
+ componentOrChildren: React.ComponentType<any> | (() => React.ReactElement),
17
+ options: { headerShown?: boolean } = {}
18
+ ): StackScreen {
19
+ const isChildrenFunction = typeof componentOrChildren === "function" &&
20
+ !(componentOrChildren.prototype && componentOrChildren.prototype.isReactComponent);
21
+
22
+ if (isChildrenFunction) {
23
+ return {
24
+ name,
25
+ options: { headerShown: false, ...options },
26
+ children: componentOrChildren as () => React.ReactElement,
27
+ };
28
+ }
29
+ return {
30
+ name,
31
+ component: componentOrChildren as any,
32
+ options: { headerShown: false, ...options },
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Create a screen with props
38
+ */
39
+ export function createScreenWithProps<P extends Record<string, unknown>>(
40
+ name: string,
41
+ component: React.ComponentType<P>,
42
+ props: P,
43
+ options: { headerShown?: boolean } = {}
44
+ ): StackScreen {
45
+ return {
46
+ name,
47
+ options: { headerShown: false, ...options },
48
+ children: (() => React.createElement(component, props)) as () => React.ReactElement,
49
+ };
50
+ }
51
+
52
+ /**
53
+ * Convert additional screen to stack screen
54
+ */
55
+ export function convertAdditionalScreen(screen: AdditionalScreen): StackScreen {
56
+ const stackScreen: any = { name: screen.name };
57
+ if (screen.component) stackScreen.component = screen.component;
58
+ if (screen.children) stackScreen.children = screen.children;
59
+ if (screen.options) stackScreen.options = screen.options;
60
+ return stackScreen as StackScreen;
61
+ }
62
+
63
+ /**
64
+ * Create conditional screen
65
+ */
66
+ export function createConditionalScreen(
67
+ condition: boolean,
68
+ screenFactory: () => StackScreen
69
+ ): StackScreen | null {
70
+ return condition ? screenFactory() : null;
71
+ }
72
+
73
+ /**
74
+ * Combine screens excluding null values
75
+ */
76
+ export function combineScreens(...screens: (StackScreen | null | StackScreen[])[]): StackScreen[] {
77
+ const result: StackScreen[] = [];
78
+ for (const screen of screens) {
79
+ if (screen === null) continue;
80
+ if (Array.isArray(screen)) {
81
+ result.push(...screen);
82
+ } else {
83
+ result.push(screen);
84
+ }
85
+ }
86
+ return result;
87
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * User Profile Utilities
3
+ *
4
+ * Helper functions for creating user profile configurations.
5
+ */
6
+
7
+ import type { UserProfileDisplay } from "../navigation/types";
8
+
9
+ export interface UserProfileConfig {
10
+ displayName?: string;
11
+ userId?: string;
12
+ isAnonymous?: boolean;
13
+ avatarUrl?: string;
14
+ }
15
+
16
+ export interface CreateUserProfileParams {
17
+ profileData?: UserProfileConfig;
18
+ t: (key: string, params?: Record<string, string | number>) => string;
19
+ onSignIn?: () => void;
20
+ }
21
+
22
+ /**
23
+ * Create user profile display configuration
24
+ */
25
+ export function createUserProfileDisplay(params: CreateUserProfileParams): UserProfileDisplay {
26
+ const { profileData, t, onSignIn } = params;
27
+
28
+ const isAnonymous = profileData?.isAnonymous ?? true;
29
+ const anonymousName = t("settings.profile.anonymousName");
30
+
31
+ return {
32
+ displayName: profileData?.displayName || anonymousName,
33
+ userId: profileData?.userId ?? undefined,
34
+ isAnonymous,
35
+ avatarUrl: profileData?.avatarUrl ?? undefined,
36
+ onPress: isAnonymous ? onSignIn : undefined,
37
+ accountSettingsRoute: isAnonymous ? undefined : "Account",
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Create benefits list for anonymous users
43
+ */
44
+ export function createAnonymousBenefits(t: (key: string) => string): string[] {
45
+ return [
46
+ t("settings.profile.benefits.saveHistory"),
47
+ t("settings.profile.benefits.syncDevices"),
48
+ t("settings.profile.benefits.cloudSync"),
49
+ t("settings.profile.benefits.secureBackup"),
50
+ ];
51
+ }