@umituz/react-native-settings 4.23.82 → 4.23.84

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 (24) hide show
  1. package/package.json +1 -1
  2. package/src/domains/disclaimer/presentation/screens/DisclaimerScreen.tsx +15 -1
  3. package/src/domains/faqs/presentation/screens/FAQScreen.tsx +25 -23
  4. package/src/domains/feedback/presentation/components/FeedbackForm.styles.ts +51 -0
  5. package/src/domains/feedback/presentation/components/FeedbackForm.tsx +3 -49
  6. package/src/domains/feedback/presentation/components/FeedbackModal.tsx +16 -19
  7. package/src/domains/gamification/components/GamificationScreen/GamificationScreen.tsx +54 -57
  8. package/src/domains/legal/presentation/screens/LegalContentScreen.tsx +8 -8
  9. package/src/domains/legal/presentation/screens/LegalScreen.tsx +14 -3
  10. package/src/domains/notifications/index.ts +1 -1
  11. package/src/domains/notifications/presentation/screens/NotificationsScreen.tsx +53 -26
  12. package/src/domains/notifications/reminders/presentation/components/ReminderForm.constants.ts +35 -0
  13. package/src/domains/notifications/reminders/presentation/components/ReminderForm.styles.ts +22 -0
  14. package/src/domains/notifications/reminders/presentation/components/ReminderForm.tsx +13 -57
  15. package/src/domains/notifications/reminders/presentation/screens/ReminderListScreen.tsx +25 -10
  16. package/src/domains/video-tutorials/presentation/components/VideoTutorialCard.tsx +17 -14
  17. package/src/domains/video-tutorials/presentation/screens/VideoTutorialsScreen.tsx +58 -33
  18. package/src/presentation/components/SettingsFooter.tsx +3 -3
  19. package/src/presentation/navigation/SettingsStackNavigator.tsx +32 -174
  20. package/src/presentation/navigation/hooks/index.ts +1 -0
  21. package/src/presentation/navigation/hooks/useSettingsScreens.ts +163 -0
  22. package/src/presentation/screens/SettingsScreen.tsx +0 -1
  23. package/src/presentation/screens/components/SettingsHeader.tsx +2 -5
  24. package/src/utils/appUtils.ts +7 -0
@@ -0,0 +1,22 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import type { useAppDesignTokens } from '@umituz/react-native-design-system';
3
+
4
+ export const createReminderFormStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
5
+ StyleSheet.create({
6
+ container: {
7
+ flex: 1,
8
+ padding: 16,
9
+ backgroundColor: tokens.colors.surface,
10
+ },
11
+ section: { marginBottom: 20 },
12
+ label: { color: tokens.colors.textPrimary, marginBottom: 8 },
13
+ input: {
14
+ backgroundColor: tokens.colors.surfaceSecondary,
15
+ borderRadius: 8,
16
+ padding: 12,
17
+ fontSize: 16,
18
+ color: tokens.colors.textPrimary,
19
+ },
20
+ multilineInput: { minHeight: 80, textAlignVertical: 'top' },
21
+ buttonRow: { flexDirection: 'row', gap: 12, marginTop: 24 },
22
+ });
@@ -11,44 +11,20 @@ import { TimePresetSelector } from './TimePresetSelector';
11
11
  import { FrequencySelector } from './FrequencySelector';
12
12
  import { WeekdaySelector } from './WeekdaySelector';
13
13
  import { FormButton } from './FormButton';
14
+ import {
15
+ DEFAULT_HOUR,
16
+ DEFAULT_MINUTE,
17
+ DEFAULT_WEEKDAY,
18
+ MAX_TITLE_LENGTH,
19
+ MAX_BODY_LENGTH,
20
+ VALID_HOUR_RANGE,
21
+ VALID_MINUTE_RANGE,
22
+ VALID_WEEKDAY_RANGE,
23
+ type ReminderFormProps,
24
+ } from './ReminderForm.constants';
25
+ import { createReminderFormStyles as createStyles } from './ReminderForm.styles';
14
26
  import { DEFAULT_TIME_PRESETS, FREQUENCY_OPTIONS } from '../../infrastructure/config/reminderPresets';
15
- import type { Reminder, ReminderFrequency, CreateReminderInput, TimePreset } from '../../../infrastructure/services/types';
16
-
17
- // Constants for magic numbers
18
- const DEFAULT_HOUR = 9;
19
- const DEFAULT_MINUTE = 0;
20
- const DEFAULT_WEEKDAY = 2; // Tuesday
21
- const MAX_TITLE_LENGTH = 100;
22
- const MAX_BODY_LENGTH = 500;
23
-
24
- // Validation constants
25
- const VALID_HOUR_RANGE = { min: 0, max: 23 } as const;
26
- const VALID_MINUTE_RANGE = { min: 0, max: 59 } as const;
27
- const VALID_WEEKDAY_RANGE = { min: 0, max: 6 } as const;
28
-
29
- export interface ReminderFormTranslations {
30
- titleLabel: string;
31
- titlePlaceholder: string;
32
- bodyLabel: string;
33
- bodyPlaceholder: string;
34
- timeLabel: string;
35
- frequencyLabel: string;
36
- weekdayLabel: string;
37
- saveButton: string;
38
- cancelButton: string;
39
- customTimeLabel: string;
40
- getPresetLabel: (key: string) => string;
41
- getFrequencyLabel: (key: string) => string;
42
- getWeekdayLabel: (key: string) => string;
43
- }
44
-
45
- export interface ReminderFormProps {
46
- initialData?: Reminder;
47
- translations: ReminderFormTranslations;
48
- onSave: (data: CreateReminderInput) => void;
49
- onCancel: () => void;
50
- timePresets?: TimePreset[];
51
- }
27
+ import type { ReminderFrequency, TimePreset } from '../../../infrastructure/services/types';
52
28
 
53
29
  export const ReminderForm: React.FC<ReminderFormProps> = ({
54
30
  initialData,
@@ -207,23 +183,3 @@ export const ReminderForm: React.FC<ReminderFormProps> = ({
207
183
  </ScrollView>
208
184
  );
209
185
  };
210
-
211
- const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
212
- StyleSheet.create({
213
- container: {
214
- flex: 1,
215
- padding: 16,
216
- backgroundColor: tokens.colors.surface,
217
- },
218
- section: { marginBottom: 20 },
219
- label: { color: tokens.colors.textPrimary, marginBottom: 8 },
220
- input: {
221
- backgroundColor: tokens.colors.surfaceSecondary,
222
- borderRadius: 8,
223
- padding: 12,
224
- fontSize: 16,
225
- color: tokens.colors.textPrimary,
226
- },
227
- multilineInput: { minHeight: 80, textAlignVertical: 'top' },
228
- buttonRow: { flexDirection: 'row', gap: 12, marginTop: 24 },
229
- });
@@ -5,8 +5,15 @@
5
5
 
6
6
  import React, { useMemo, useCallback } from 'react';
7
7
  import { View, FlatList, StyleSheet, TouchableOpacity } from 'react-native';
8
- import { AtomicText, AtomicIcon, AtomicSpinner } from '@umituz/react-native-design-system';
9
- import { useAppDesignTokens } from '@umituz/react-native-design-system';
8
+ import {
9
+ AtomicText,
10
+ AtomicIcon,
11
+ AtomicSpinner,
12
+ ScreenLayout,
13
+ NavigationHeader,
14
+ useAppNavigation,
15
+ useAppDesignTokens
16
+ } from '@umituz/react-native-design-system';
10
17
  import { ReminderItem } from '../components/ReminderItem';
11
18
  import { useReminders, useRemindersLoading } from '../../infrastructure/storage/RemindersStore';
12
19
  import { useReminderActions } from '../../infrastructure/hooks/useReminderActions';
@@ -25,6 +32,7 @@ export const ReminderListScreen: React.FC<ReminderListScreenProps> = ({
25
32
  onEditPress,
26
33
  maxReminders = 20,
27
34
  }) => {
35
+ const navigation = useAppNavigation();
28
36
  const tokens = useAppDesignTokens();
29
37
  const styles = useMemo(() => createStyles(tokens), [tokens]);
30
38
 
@@ -69,32 +77,39 @@ export const ReminderListScreen: React.FC<ReminderListScreenProps> = ({
69
77
 
70
78
  const keyExtractor = useCallback((item: Reminder) => item.id, []);
71
79
 
80
+ const header = (
81
+ <NavigationHeader
82
+ title={translations.screenTitle}
83
+ onBackPress={() => navigation.goBack()}
84
+ />
85
+ );
86
+
72
87
  if (isLoading) {
73
88
  return (
74
- <View style={[styles.loadingContainer, { backgroundColor: tokens.colors.surface }]}>
89
+ <ScreenLayout header={header}>
75
90
  <AtomicSpinner size="lg" color="primary" fullContainer />
76
- </View>
91
+ </ScreenLayout>
77
92
  );
78
93
  }
79
94
 
80
95
  return (
81
- <View style={{ flex: 1 }}>
96
+ <ScreenLayout header={header}>
82
97
  <FlatList
83
98
  data={reminders}
84
99
  renderItem={renderItem}
85
100
  keyExtractor={keyExtractor}
86
101
  ListEmptyComponent={renderEmpty}
87
- contentContainerStyle={[styles.listContent, { backgroundColor: tokens.colors.surface }]}
102
+ contentContainerStyle={styles.listContent}
88
103
  showsVerticalScrollIndicator={false}
89
104
  />
90
105
 
91
106
  {canAddMore && (
92
107
  <TouchableOpacity style={styles.fab} onPress={onAddPress} activeOpacity={0.8}>
93
- <AtomicIcon name="add" size="md" color="onSurface" />
108
+ <AtomicIcon name="add" size="md" color="onPrimary" />
94
109
  <AtomicText type="bodyMedium" style={styles.fabText}>{translations.addButtonLabel}</AtomicText>
95
110
  </TouchableOpacity>
96
111
  )}
97
- </View>
112
+ </ScreenLayout>
98
113
  );
99
114
  };
100
115
 
@@ -102,7 +117,7 @@ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
102
117
  StyleSheet.create({
103
118
  loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' },
104
119
  listContent: { padding: 16, paddingBottom: 100, flexGrow: 1 },
105
- emptyContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 32 },
120
+ emptyContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 32, paddingTop: 100 },
106
121
  emptyIconContainer: {
107
122
  width: 80,
108
123
  height: 80,
@@ -127,5 +142,5 @@ const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
127
142
  justifyContent: 'center',
128
143
  gap: 8,
129
144
  },
130
- fabText: { color: tokens.colors.surface, fontWeight: '600' },
145
+ fabText: { color: tokens.colors.onPrimary, fontWeight: '600' },
131
146
  });
@@ -44,18 +44,19 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
44
44
  style={[styles.thumbnail, horizontal && styles.horizontalThumbnail]}
45
45
  resizeMode="cover"
46
46
  />
47
- <View style={[styles.durationBadge, { backgroundColor: "rgba(0,0,0,0.7)" }]}>
48
- <AtomicText style={styles.durationText}>{formatDuration(tutorial.duration)}</AtomicText>
47
+ <View style={styles.durationBadge}>
48
+ <AtomicText type="labelSmall" style={styles.durationText}>{formatDuration(tutorial.duration)}</AtomicText>
49
49
  </View>
50
50
  {tutorial.featured && (
51
51
  <View style={[styles.featuredBadge, { backgroundColor: tokens.colors.primary }]}>
52
- <AtomicText style={[styles.featuredText, { color: tokens.colors.onPrimary }]}>Featured</AtomicText>
52
+ <AtomicText type="labelSmall" style={[styles.featuredText, { color: tokens.colors.onPrimary }]}>Featured</AtomicText>
53
53
  </View>
54
54
  )}
55
55
  </View>
56
56
 
57
57
  <View style={styles.content}>
58
58
  <AtomicText
59
+ type={horizontal ? "titleMedium" : "titleLarge"}
59
60
  style={[styles.title, horizontal && styles.horizontalTitle]}
60
61
  numberOfLines={2}
61
62
  >
@@ -63,6 +64,8 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
63
64
  </AtomicText>
64
65
 
65
66
  <AtomicText
67
+ type={horizontal ? "bodySmall" : "bodyMedium"}
68
+ color="textSecondary"
66
69
  style={[styles.description, horizontal && styles.horizontalDescription]}
67
70
  numberOfLines={horizontal ? 2 : 3}
68
71
  >
@@ -70,10 +73,10 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
70
73
  </AtomicText>
71
74
 
72
75
  <View style={styles.metadata}>
73
- <AtomicText style={styles.category}>
76
+ <AtomicText type="labelSmall" color="textTertiary" style={styles.category}>
74
77
  {tutorial.category.replace("-", " ")}
75
78
  </AtomicText>
76
- <AtomicText style={styles.difficulty}>
79
+ <AtomicText type="labelSmall" color="textSecondary" style={styles.difficulty}>
77
80
  {tutorial.difficulty}
78
81
  </AtomicText>
79
82
  </View>
@@ -88,16 +91,16 @@ const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) => StyleSheet.
88
91
  imageContainer: { position: "relative" },
89
92
  thumbnail: { width: "100%", height: 180 },
90
93
  horizontalThumbnail: { height: 140 },
91
- durationBadge: { position: "absolute", bottom: 8, right: 8, paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4 },
92
- durationText: { color: tokens.colors.textInverse, fontSize: 12, fontWeight: "500" },
94
+ durationBadge: { position: "absolute", bottom: 8, right: 8, paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, backgroundColor: "rgba(0,0,0,0.7)" },
95
+ durationText: { color: tokens.colors.textInverse },
93
96
  featuredBadge: { position: "absolute", top: 8, left: 8, paddingHorizontal: 8, paddingVertical: 4, borderRadius: 4 },
94
- featuredText: { fontSize: 11, fontWeight: "600" },
97
+ featuredText: { fontWeight: "600" },
95
98
  content: { padding: 12 },
96
- title: { fontSize: tokens.typography.titleMedium.fontSize, fontWeight: "600", marginBottom: 6, color: tokens.colors.textPrimary },
97
- horizontalTitle: { fontSize: tokens.typography.bodyLarge.fontSize },
98
- description: { fontSize: tokens.typography.bodyMedium.fontSize, lineHeight: 20, marginBottom: 8, color: tokens.colors.textSecondary },
99
- horizontalDescription: { fontSize: tokens.typography.bodySmall.fontSize, lineHeight: 16, marginBottom: 6 },
99
+ title: { fontWeight: "600", marginBottom: 6, color: tokens.colors.textPrimary },
100
+ horizontalTitle: {},
101
+ description: { marginBottom: 8 },
102
+ horizontalDescription: { marginBottom: 6 },
100
103
  metadata: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" },
101
- category: { fontSize: 12, textTransform: "capitalize", fontWeight: "500", color: tokens.colors.textTertiary },
102
- difficulty: { fontSize: 12, textTransform: "capitalize", fontWeight: "500", color: tokens.colors.textSecondary },
104
+ category: { textTransform: "capitalize", fontWeight: "500" },
105
+ difficulty: { textTransform: "capitalize", fontWeight: "500" },
103
106
  });
@@ -18,6 +18,8 @@ import {
18
18
  ScreenLayout,
19
19
  AtomicSpinner,
20
20
  AtomicText,
21
+ useAppNavigation,
22
+ NavigationHeader,
21
23
  } from "@umituz/react-native-design-system";
22
24
  import type { DesignTokens } from "@umituz/react-native-design-system";
23
25
  import type { VideoTutorial } from "../../types";
@@ -46,6 +48,7 @@ export const VideoTutorialsScreen: React.FC<VideoTutorialsScreenProps> = React.m
46
48
  onTutorialPress,
47
49
  }) => {
48
50
  const tokens = useAppDesignTokens();
51
+ const navigation = useAppNavigation();
49
52
  const styles = getStyles(tokens);
50
53
 
51
54
  const handleTutorialPress = React.useCallback(
@@ -67,26 +70,39 @@ export const VideoTutorialsScreen: React.FC<VideoTutorialsScreenProps> = React.m
67
70
  [handleTutorialPress]
68
71
  );
69
72
 
70
- if (isLoading) return <AtomicSpinner size="lg" fullContainer />;
71
-
72
73
  const hasFeatured = featuredTutorials && featuredTutorials.length > 0;
73
74
  const hasTutorials = tutorials && tutorials.length > 0;
74
75
 
75
- if (!hasTutorials && !hasFeatured) {
76
+ const header = (
77
+ <NavigationHeader
78
+ title={title}
79
+ onBackPress={() => navigation.goBack()}
80
+ />
81
+ );
82
+
83
+ if (isLoading) {
76
84
  return (
77
- <View style={styles.emptyContainer}>
78
- <AtomicText color="secondary" type="bodyLarge">{emptyMessage}</AtomicText>
79
- </View>
85
+ <ScreenLayout header={header}>
86
+ <AtomicSpinner size="lg" fullContainer color="primary" />
87
+ </ScreenLayout>
80
88
  );
81
89
  }
82
90
 
83
- return (
84
- <ScreenLayout scrollable={false} edges={["top", "bottom"]}>
85
- <AtomicText style={styles.title}>{title}</AtomicText>
91
+ if (!hasTutorials && !hasFeatured) {
92
+ return (
93
+ <ScreenLayout header={header}>
94
+ <View style={styles.emptyContainer}>
95
+ <AtomicText color="textSecondary" type="bodyLarge" style={{ textAlign: 'center' }}>{emptyMessage}</AtomicText>
96
+ </View>
97
+ </ScreenLayout>
98
+ );
99
+ }
86
100
 
101
+ const ListHeader = () => (
102
+ <>
87
103
  {hasFeatured && (
88
104
  <View style={styles.section}>
89
- <AtomicText color="secondary" style={styles.sectionTitle}>{featuredTitle}</AtomicText>
105
+ <AtomicText color="textSecondary" type="titleLarge" style={styles.sectionTitle}>{featuredTitle}</AtomicText>
90
106
  <FlatList
91
107
  data={featuredTutorials}
92
108
  renderItem={renderFeaturedItem}
@@ -97,38 +113,47 @@ export const VideoTutorialsScreen: React.FC<VideoTutorialsScreenProps> = React.m
97
113
  />
98
114
  </View>
99
115
  )}
100
-
101
116
  {hasTutorials && (
102
- <View style={styles.section}>
103
- <AtomicText color="secondary" style={styles.sectionTitle}>{allTutorialsTitle}</AtomicText>
104
- <FlatList
105
- data={tutorials}
106
- renderItem={renderTutorialItem}
107
- keyExtractor={(item) => item.id}
108
- showsVerticalScrollIndicator={false}
109
- contentContainerStyle={styles.verticalList}
110
- />
111
- </View>
117
+ <AtomicText color="textSecondary" type="titleLarge" style={styles.sectionTitle}>{allTutorialsTitle}</AtomicText>
112
118
  )}
119
+ </>
120
+ );
121
+
122
+ return (
123
+ <ScreenLayout header={header} scrollable={false}>
124
+ <FlatList
125
+ data={tutorials}
126
+ renderItem={renderTutorialItem}
127
+ keyExtractor={(item) => item.id}
128
+ showsVerticalScrollIndicator={false}
129
+ contentContainerStyle={styles.verticalList}
130
+ ListHeaderComponent={ListHeader}
131
+ />
113
132
  </ScreenLayout>
114
133
  );
115
134
  }
116
135
  );
117
136
 
118
137
  const getStyles = (tokens: DesignTokens) => StyleSheet.create({
119
- title: {
120
- fontSize: tokens.typography.headlineLarge.fontSize,
121
- color: tokens.colors.textPrimary,
122
- fontWeight: "600",
123
- marginBottom: 24,
138
+ section: {
139
+ marginBottom: tokens.spacing.lg,
124
140
  },
125
- section: { marginBottom: 24 },
126
141
  sectionTitle: {
127
- fontSize: tokens.typography.titleLarge.fontSize,
128
- fontWeight: "500",
129
- marginBottom: 12,
142
+ fontWeight: "600",
143
+ marginBottom: tokens.spacing.sm,
144
+ paddingHorizontal: tokens.spacing.md,
145
+ },
146
+ horizontalList: {
147
+ paddingHorizontal: tokens.spacing.md,
148
+ },
149
+ verticalList: {
150
+ paddingBottom: tokens.spacing.xl,
151
+ paddingHorizontal: tokens.spacing.md,
152
+ },
153
+ emptyContainer: {
154
+ flex: 1,
155
+ justifyContent: "center",
156
+ alignItems: "center",
157
+ padding: tokens.spacing.lg,
130
158
  },
131
- horizontalList: { paddingRight: 16 },
132
- verticalList: { paddingBottom: 16 },
133
- emptyContainer: { flex: 1, justifyContent: "center", alignItems: "center", padding: 20 },
134
159
  });
@@ -13,9 +13,9 @@ export const SettingsFooter: React.FC<SettingsFooterProps> = ({
13
13
  appVersion,
14
14
  versionLabel,
15
15
  }) => {
16
- const displayText = versionText || (appVersion && versionLabel
17
- ? `${versionLabel} ${appVersion}`
18
- : appVersion);
16
+ const displayText = versionText || (appVersion
17
+ ? (versionLabel ? `${versionLabel} ${appVersion}` : `Version ${appVersion}`)
18
+ : undefined);
19
19
 
20
20
  if (!displayText) return null;
21
21
 
@@ -6,7 +6,12 @@
6
6
  */
7
7
 
8
8
  import React from "react";
9
- import { useAppDesignTokens, StackNavigator, type StackScreen, type StackNavigatorConfig } from "@umituz/react-native-design-system";
9
+ import {
10
+ useAppDesignTokens,
11
+ StackNavigator,
12
+ type StackScreen,
13
+ type StackNavigatorConfig,
14
+ } from "@umituz/react-native-design-system";
10
15
  import { useLocalization, LanguageSelectionScreen } from "../../domains/localization";
11
16
  import { NotificationSettingsScreen } from "../../domains/notifications";
12
17
  import { AccountScreen } from "@umituz/react-native-auth";
@@ -16,30 +21,31 @@ import { FAQScreen } from "../../domains/faqs";
16
21
  import { AboutScreen } from "../../domains/about";
17
22
  import { LegalScreen } from "../../domains/legal";
18
23
  import { GamificationScreen } from "../../domains/gamification";
19
- import { useNavigationHandlers } from "./hooks";
24
+ import { useNavigationHandlers, useSettingsScreens } from "./hooks";
20
25
  import {
21
26
  createNotificationTranslations,
22
27
  createQuietHoursTranslations,
23
28
  createLegalScreenProps,
24
29
  } from "./utils";
25
- import type { SettingsStackParamList, SettingsStackNavigatorProps, AdditionalScreen } from "./types";
30
+ import type { SettingsStackParamList, SettingsStackNavigatorProps } from "./types";
26
31
 
27
- export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
28
- appInfo,
29
- legalUrls,
30
- faqData,
31
- config = {},
32
- showUserProfile = false,
33
- userProfile,
34
- accountConfig,
35
- additionalScreens = [],
36
- devSettings,
37
- customSections = [],
38
- showHeader = true,
39
- showCloseButton = false,
40
- onClose,
41
- gamificationConfig,
42
- }) => {
32
+ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = (props) => {
33
+ const {
34
+ appInfo,
35
+ legalUrls,
36
+ faqData,
37
+ config = {},
38
+ showUserProfile = false,
39
+ userProfile,
40
+ accountConfig,
41
+ additionalScreens = [],
42
+ devSettings,
43
+ customSections = [],
44
+ showHeader = true,
45
+ showCloseButton = false,
46
+ onClose,
47
+ gamificationConfig,
48
+ } = props;
43
49
  const tokens = useAppDesignTokens();
44
50
  const { t } = useLocalization();
45
51
  const { handlePrivacyPress, handleTermsPress, handleEulaPress, aboutConfig } =
@@ -47,21 +53,9 @@ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
47
53
 
48
54
  const screenOptions = React.useMemo(
49
55
  () => ({
50
- headerStyle: {
51
- backgroundColor: tokens.colors.surface,
52
- borderBottomColor: tokens.colors.borderLight,
53
- borderBottomWidth: 1,
54
- elevation: 0,
55
- shadowOpacity: 0,
56
- },
57
- headerTintColor: tokens.colors.textPrimary,
58
- headerTitleStyle: {
59
- color: tokens.colors.textPrimary,
60
- fontWeight: "600" as const,
61
- },
62
- headerBackTitle: t("settings.title"),
56
+ headerShown: false,
63
57
  }),
64
- [tokens, t]
58
+ []
65
59
  );
66
60
 
67
61
  const notificationTranslations = React.useMemo(() => createNotificationTranslations(t), [t]);
@@ -71,150 +65,14 @@ export const SettingsStackNavigator: React.FC<SettingsStackNavigatorProps> = ({
71
65
  [t, handlePrivacyPress, handleTermsPress, handleEulaPress]
72
66
  );
73
67
 
74
- const screens = React.useMemo(() => {
75
- const baseScreens: StackScreen[] = [
76
- {
77
- name: "SettingsMain",
78
- options: { headerShown: false },
79
- children: () => (
80
- <SettingsScreen
81
- config={config}
82
- appVersion={appInfo.version}
83
- showUserProfile={showUserProfile}
84
- userProfile={userProfile}
85
- devSettings={devSettings}
86
- customSections={customSections}
87
- showHeader={showHeader}
88
- showCloseButton={showCloseButton}
89
- onClose={onClose}
90
- />
91
- ),
92
- },
93
- {
94
- name: "Appearance",
95
- component: AppearanceScreen,
96
- options: { headerShown: false },
97
- },
98
- {
99
- name: "About",
100
- options: { headerTitle: t("settings.about.title") },
101
- children: () => <AboutScreen config={aboutConfig} />,
102
- },
103
- {
104
- name: "Legal",
105
- options: { headerTitle: t("settings.legal.title") },
106
- children: () => <LegalScreen {...legalScreenProps} />,
107
- },
108
- {
109
- name: "Notifications",
110
- options: { headerShown: false },
111
- children: () => (
112
- <NotificationSettingsScreen
113
- translations={notificationTranslations}
114
- quietHoursTranslations={quietHoursTranslations}
115
- />
116
- ),
117
- },
118
- ];
119
-
120
- // FAQ screen - conditionally add
121
- const faqScreen: StackScreen | null = (faqData && faqData.categories.length > 0)
122
- ? {
123
- name: "FAQ",
124
- options: { headerTitle: t("settings.faqs.title") },
125
- children: () => (
126
- <FAQScreen
127
- categories={faqData.categories}
128
- searchPlaceholder={t("settings.faqs.searchPlaceholder")}
129
- emptySearchTitle={t("settings.faqs.emptySearchTitle")}
130
- emptySearchMessage={t("settings.faqs.emptySearchMessage")}
131
- headerTitle={t("settings.faqs.headerTitle")}
132
- />
133
- ),
134
- }
135
- : null;
136
-
137
- // Additional screens - map to StackScreen format
138
- const additionalStackScreens: StackScreen[] = (additionalScreens as readonly AdditionalScreen[]).map((screen: AdditionalScreen): StackScreen => {
139
- // Create base screen object
140
- const stackScreen: Record<string, unknown> = {
141
- name: screen.name,
142
- };
143
-
144
- // Conditionally add properties
145
- if (screen.component) {
146
- stackScreen.component = screen.component;
147
- }
148
- if (screen.children) {
149
- stackScreen.children = screen.children;
150
- }
151
- if (screen.options) {
152
- stackScreen.options = screen.options;
153
- }
154
-
155
- // Type assertion to StackScreen
156
- return stackScreen as unknown as StackScreen;
157
- });
158
-
159
- // Gamification screen - conditionally add
160
- const gamificationScreen: StackScreen | null = gamificationConfig?.enabled
161
- ? {
162
- name: "Gamification",
163
- options: { headerTitle: t("settings.gamification.title") },
164
- children: () => <GamificationScreen config={gamificationConfig} />,
165
- }
166
- : null;
167
-
168
- // Language selection screen
169
- const languageScreen: StackScreen = {
170
- name: "LanguageSelection",
171
- options: { headerShown: false },
172
- children: () => (
173
- <LanguageSelectionScreen
174
- headerTitle={t("settings.language.title")}
175
- searchPlaceholder={t("settings.languageSelection.searchPlaceholder")}
176
- />
177
- ),
178
- };
179
-
180
- // Account screen - conditionally add
181
- const accountScreen: StackScreen | null = accountConfig
182
- ? {
183
- name: "Account",
184
- options: { headerTitle: t("settings.account.title") },
185
- children: () => <AccountScreen config={accountConfig} />,
186
- }
187
- : null;
188
-
189
- // Compose final list using spread operator (immutable)
190
- return [
191
- ...baseScreens,
192
- ...(faqScreen ? [faqScreen] : []),
193
- ...additionalStackScreens,
194
- ...(gamificationScreen ? [gamificationScreen] : []),
195
- languageScreen,
196
- ...(accountScreen ? [accountScreen] : []),
197
- ];
198
- }, [
199
- t,
200
- showHeader,
201
- showCloseButton,
202
- onClose,
203
- config,
204
- appInfo.version,
205
- showUserProfile,
206
- userProfile,
207
- devSettings,
208
- customSections,
68
+ const screens = useSettingsScreens({
69
+ ...props,
209
70
  aboutConfig,
210
- legalScreenProps,
71
+ legalProps: legalScreenProps,
211
72
  notificationTranslations,
212
73
  quietHoursTranslations,
213
- faqData,
214
- additionalScreens,
215
- gamificationConfig,
216
- accountConfig,
217
- ]);
74
+ t,
75
+ });
218
76
 
219
77
  const navigatorConfig: StackNavigatorConfig<SettingsStackParamList> = {
220
78
  initialRouteName: "SettingsMain",
@@ -3,3 +3,4 @@
3
3
  */
4
4
 
5
5
  export { useNavigationHandlers } from "./useNavigationHandlers";
6
+ export { useSettingsScreens } from "./useSettingsScreens";