@umituz/react-native-settings 4.17.26 → 4.17.30

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 (41) hide show
  1. package/package.json +15 -6
  2. package/src/domains/about/presentation/components/AboutSection.tsx +14 -71
  3. package/src/domains/appearance/application/ports/IAppearanceRepository.ts +8 -0
  4. package/src/domains/appearance/hooks/index.ts +1 -1
  5. package/src/domains/appearance/hooks/useAppearance.ts +18 -58
  6. package/src/domains/appearance/hooks/useAppearanceActions.ts +20 -128
  7. package/src/domains/appearance/infrastructure/repositories/AppearanceRepository.ts +34 -0
  8. package/src/domains/appearance/infrastructure/services/AppearanceService.ts +51 -0
  9. package/src/domains/appearance/presentation/components/AppearanceSection.tsx +2 -2
  10. package/src/domains/appearance/presentation/hooks/mutations/useAppearanceMutations.ts +36 -0
  11. package/src/domains/appearance/presentation/hooks/queries/useAppearanceQuery.ts +15 -0
  12. package/src/domains/disclaimer/presentation/components/DisclaimerModal.tsx +37 -40
  13. package/src/domains/faqs/presentation/components/FAQSection.tsx +1 -1
  14. package/src/domains/feedback/presentation/components/FeedbackModal.tsx +11 -15
  15. package/src/domains/feedback/presentation/components/SupportSection.tsx +2 -2
  16. package/src/domains/legal/presentation/components/LegalItem.tsx +13 -129
  17. package/src/index.ts +15 -9
  18. package/src/infrastructure/repositories/SettingsRepository.ts +105 -0
  19. package/src/infrastructure/services/SettingsService.ts +47 -0
  20. package/src/presentation/components/SettingItem.tsx +77 -129
  21. package/src/presentation/components/SettingsFooter.tsx +9 -25
  22. package/src/presentation/components/SettingsSection.tsx +9 -20
  23. package/src/presentation/hooks/mutations/useSettingsMutations.ts +58 -0
  24. package/src/presentation/hooks/queries/useSettingsQuery.ts +27 -0
  25. package/src/presentation/hooks/useSettings.ts +45 -0
  26. package/src/presentation/screens/components/SettingsContent.tsx +20 -247
  27. package/src/presentation/screens/components/sections/CustomSettingsList.tsx +31 -0
  28. package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +55 -0
  29. package/src/presentation/screens/components/sections/IdentitySettingsSection.tsx +43 -0
  30. package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +47 -0
  31. package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +84 -0
  32. package/src/presentation/screens/hooks/useFeatureDetection.ts +1 -16
  33. package/src/presentation/screens/types/FeatureConfig.ts +18 -0
  34. package/src/presentation/screens/types/SettingsConfig.ts +7 -0
  35. package/src/domains/appearance/infrastructure/services/appearanceService.ts +0 -301
  36. package/src/domains/appearance/infrastructure/storage/appearanceStorage.ts +0 -120
  37. package/src/domains/appearance/infrastructure/stores/appearanceStore.ts +0 -132
  38. package/src/infrastructure/storage/SettingsStore.ts +0 -189
  39. package/src/infrastructure/storage/__tests__/SettingsStore.test.tsx +0 -302
  40. package/src/presentation/components/CloudSyncSetting.tsx +0 -58
  41. /package/src/{domain/repositories → application/ports}/ISettingsRepository.ts +0 -0
@@ -1,66 +1,23 @@
1
- /**
2
- * Settings Content Component
3
- * Renders all settings sections and custom content
4
- */
5
-
6
1
  import React, { useMemo } from "react";
7
2
  import { View, ScrollView, StyleSheet } from "react-native";
8
3
  import { useSafeAreaInsets } from "react-native-safe-area-context";
9
4
  import { useResponsiveDesignTokens } from "@umituz/react-native-design-system";
10
5
  import { useLocalization } from "@umituz/react-native-localization";
11
6
  import { SettingsFooter } from "../../components/SettingsFooter";
12
- import { ProfileSection } from "@umituz/react-native-auth";
13
7
  import { SettingsSection } from "../../components/SettingsSection";
14
8
  import { DevSettingsSection, DevSettingsProps } from "../../components/DevSettingsSection";
15
- import { NotificationsSection } from "@umituz/react-native-notifications";
16
- import { AboutSection } from "../../../domains/about/presentation/components/AboutSection";
17
- import { LegalSection } from "../../../domains/legal/presentation/components/LegalSection";
18
- import { AppearanceSection } from "../../../domains/appearance/presentation/components/AppearanceSection";
19
- import { LanguageSection } from "@umituz/react-native-localization";
20
- import { SupportSection } from "../../../domains/feedback/presentation/components/SupportSection";
21
- import { SettingItem } from "../../components/SettingItem";
9
+ import { DisclaimerSetting } from "../../../domains/disclaimer";
10
+ import { ProfileSectionLoader } from "./sections/ProfileSectionLoader";
11
+ import { FeatureSettingsSection } from "./sections/FeatureSettingsSection";
12
+ import { IdentitySettingsSection } from "./sections/IdentitySettingsSection";
13
+ import { SupportSettingsSection } from "./sections/SupportSettingsSection";
14
+ import { CustomSettingsList } from "./sections/CustomSettingsList";
22
15
  import type { NormalizedConfig } from "../utils/normalizeConfig";
23
16
  import type { CustomSettingsSection } from "../types";
24
17
 
25
- // Optional FAQ component
26
- let FAQSection: React.ComponentType<any> | null = null;
27
- try {
28
- // eslint-disable-next-line @typescript-eslint/no-require-imports
29
- const module = require("@umituz/react-native-faqs");
30
- if (module?.FAQSection) {
31
- FAQSection = module.FAQSection;
32
- }
33
- } catch {
34
- // Package not available
35
- }
36
-
37
- // Optional disclaimer component
38
- let DisclaimerSetting: React.ComponentType<any> | null = null;
39
- try {
40
- // eslint-disable-next-line @typescript-eslint/no-require-imports
41
- const module = require("@umituz/react-native-disclaimer");
42
- if (module?.DisclaimerSetting) {
43
- DisclaimerSetting = module.DisclaimerSetting;
44
- }
45
- } catch {
46
- // Package not available
47
- }
48
-
49
- // Optional subscription component
50
- let SubscriptionSection: React.ComponentType<any> | null = null;
51
- try {
52
- // eslint-disable-next-line @typescript-eslint/no-require-imports
53
- const module = require("@umituz/react-native-subscription");
54
- if (module?.SubscriptionSection) {
55
- SubscriptionSection = module.SubscriptionSection;
56
- }
57
- } catch {
58
- // Package not available
59
- }
60
-
61
18
  interface SettingsContentProps {
62
19
  normalizedConfig: NormalizedConfig;
63
- config?: any; // Original config for emptyStateText
20
+ config?: any;
64
21
  features: {
65
22
  appearance: boolean;
66
23
  language: boolean;
@@ -75,22 +32,12 @@ interface SettingsContentProps {
75
32
  faqs: boolean;
76
33
  };
77
34
  showUserProfile?: boolean;
78
- userProfile?: {
79
- displayName?: string;
80
- userId?: string;
81
- isAnonymous?: boolean;
82
- avatarUrl?: string;
83
- accountSettingsRoute?: string;
84
- onPress?: () => void;
85
- anonymousDisplayName?: string;
86
- avatarServiceUrl?: string;
87
- };
35
+ userProfile?: any;
88
36
  showFooter?: boolean;
89
37
  footerText?: string;
90
38
  appVersion?: string;
91
39
  customSections?: CustomSettingsSection[];
92
40
  showCloseButton?: boolean;
93
- /** Dev settings (only shown in __DEV__ mode) */
94
41
  devSettings?: DevSettingsProps;
95
42
  }
96
43
 
@@ -126,11 +73,6 @@ export const SettingsContent: React.FC<SettingsContentProps> = ({
126
73
  [features, customSections.length]
127
74
  );
128
75
 
129
- const sortedSections = useMemo(() => {
130
- return Array.from(customSections)
131
- .sort((a, b) => (a.order ?? 999) - (b.order ?? 999));
132
- }, [customSections]);
133
-
134
76
  return (
135
77
  <ScrollView
136
78
  style={styles.scrollView}
@@ -139,191 +81,32 @@ export const SettingsContent: React.FC<SettingsContentProps> = ({
139
81
  {
140
82
  paddingTop: showCloseButton ? tokens.spacing.md : insets.top + tokens.spacing.md,
141
83
  paddingBottom: tokens.spacing.xxxl + tokens.spacing.xl,
142
- paddingHorizontal: 0,
84
+ paddingHorizontal: tokens.spacing.md,
143
85
  },
144
86
  ]}
145
87
  showsVerticalScrollIndicator={false}
146
88
  >
147
- {showUserProfile && (
148
- <View style={styles.profileContainer}>
149
- <ProfileSection
150
- profile={{
151
- displayName: userProfile?.displayName || t("settings.profile.anonymousName"),
152
- userId: userProfile?.userId,
153
- isAnonymous: userProfile?.isAnonymous ?? true,
154
- avatarUrl: userProfile?.avatarUrl,
155
- accountSettingsRoute: userProfile?.accountSettingsRoute,
156
- }}
157
- onPress={userProfile?.onPress}
158
- onSignIn={userProfile?.onPress}
159
- signInText={t("auth.signIn")}
160
- anonymousText={t("settings.profile.anonymousName")}
161
- />
162
- </View>
163
- )}
164
-
165
- {features.subscription &&
166
- SubscriptionSection &&
167
- normalizedConfig.subscription.config?.sectionConfig && (
168
- <SubscriptionSection
169
- config={normalizedConfig.subscription.config.sectionConfig}
170
- />
171
- )}
172
-
173
- {features.appearance && (
174
- <AppearanceSection
175
- config={{
176
- ...normalizedConfig.appearance.config,
177
- title: t("settings.appearance.title"),
178
- description: t("settings.appearance.description"),
179
- }}
180
- sectionTitle={t("settings.appearance.title")}
181
- />
182
- )}
183
-
184
- {features.language && (
185
- <LanguageSection
186
- config={{
187
- ...normalizedConfig.language.config,
188
- title: t("settings.languageSelection.title"),
189
- description:
190
- normalizedConfig.language.config?.description ||
191
- t("settings.languageSelection.description"),
192
- }}
193
- />
194
- )}
195
-
196
- {features.notifications && (
197
- <NotificationsSection
198
- config={{
199
- ...normalizedConfig.notifications.config,
200
- title: t("settings.notifications.title"),
201
- description: t("settings.notifications.description"),
202
- }}
203
- />
204
- )}
205
-
206
- {features.about && (
207
- <AboutSection
208
- config={{
209
- ...normalizedConfig.about.config,
210
- title: t("settings.about.title"),
211
- description: t("settings.about.description"),
212
- }}
213
- sectionTitle={t("settings.about.title")}
214
- />
215
- )}
89
+ {showUserProfile && <ProfileSectionLoader userProfile={userProfile} />}
216
90
 
217
- {features.legal && (
218
- <LegalSection
219
- config={{
220
- ...normalizedConfig.legal.config,
221
- title: t("settings.legal.title"),
222
- description: t("settings.legal.description"),
223
- }}
224
- sectionTitle={t("settings.legal.title")}
225
- />
226
- )}
91
+ <FeatureSettingsSection normalizedConfig={normalizedConfig} features={features} />
227
92
 
228
- {(features.feedback || features.rating || features.faqs) && (
229
- <SettingsSection title={t("settings.support.title")}>
230
- {(features.feedback || features.rating) && (
231
- <SupportSection
232
- renderSection={(props: any) => <>{props.children}</>}
233
- renderItem={(props: any) => <SettingItem {...props} />}
234
- feedbackConfig={{
235
- enabled: features.feedback,
236
- config: {
237
- ...normalizedConfig.feedback.config,
238
- title: normalizedConfig.feedback.config?.title || t("settings.feedback.title"),
239
- description: normalizedConfig.feedback.config?.description || t("settings.feedback.description"),
240
- }
241
- }}
242
- ratingConfig={{
243
- enabled: features.rating,
244
- config: {
245
- ...normalizedConfig.rating.config,
246
- title: normalizedConfig.rating.config?.title || t("settings.rating.title"),
247
- description: normalizedConfig.rating.config?.description || t("settings.rating.description"),
248
- }
249
- }}
250
- feedbackModalTexts={{
251
- title: t("settings.feedback.modal.title"),
252
- ratingLabel: t("settings.feedback.modal.ratingLabel"),
253
- descriptionPlaceholder: t("settings.feedback.modal.descriptionPlaceholder"),
254
- submitButton: t("settings.feedback.modal.submitButton"),
255
- submittingButton: t("settings.feedback.modal.submittingButton"),
256
- feedbackTypes: [
257
- { type: 'general', label: t("settings.feedback.types.general") },
258
- { type: 'bug_report', label: t("settings.feedback.types.bugReport") },
259
- { type: 'feature_request', label: t("settings.feedback.types.featureRequest") },
260
- { type: 'improvement', label: t("settings.feedback.types.improvement") },
261
- { type: 'other', label: t("settings.feedback.types.other") },
262
- ],
263
- defaultTitle: (type) => {
264
- const titles = {
265
- general: t("settings.feedback.types.general"),
266
- bug_report: t("settings.feedback.types.bugReport"),
267
- feature_request: t("settings.feedback.types.featureRequest"),
268
- improvement: t("settings.feedback.types.improvement"),
269
- other: t("settings.feedback.types.other"),
270
- };
271
- return titles[type] || type;
272
- },
273
- }}
274
- />
275
- )}
93
+ <IdentitySettingsSection normalizedConfig={normalizedConfig} features={features} />
276
94
 
95
+ <SupportSettingsSection normalizedConfig={normalizedConfig} features={features} />
277
96
 
278
- {features.faqs && FAQSection && (
279
- <FAQSection
280
- renderSection={(props: any) => <>{props.children}</>}
281
- renderItem={(props: any) => <SettingItem {...props} />}
282
- config={{
283
- enabled: features.faqs,
284
- ...normalizedConfig.faqs.config,
285
- title: normalizedConfig.faqs.config?.title || t("settings.faqs.title") || "FAQs",
286
- description: normalizedConfig.faqs.config?.description || t("settings.faqs.description") || "FAQs",
287
- }}
288
- />
289
- )}
290
- </SettingsSection>
291
- )}
292
-
293
- {features.disclaimer && DisclaimerSetting && (
294
- <DisclaimerSetting />
295
- )}
97
+ {features.disclaimer && <DisclaimerSetting />}
296
98
 
297
- {customSections && customSections.length > 0 && (
298
- <>
299
- {sortedSections.map((section, index) => (
300
- <SettingsSection
301
- key={section.id || `custom-${index}`}
302
- title={section.title}
303
- >
304
- {section.content}
305
- </SettingsSection>
306
- ))}
307
- </>
308
- )}
99
+ <CustomSettingsList customSections={customSections} />
309
100
 
310
101
  {!hasAnyFeatures && (
311
102
  <View style={styles.emptyContainer}>
312
- <SettingsSection
313
- title={config?.emptyStateText || t("settings.noOptionsAvailable") || "No settings available"}
314
- >
103
+ <SettingsSection title={config?.emptyStateText || t("settings.noOptionsAvailable")}>
315
104
  <View />
316
105
  </SettingsSection>
317
106
  </View>
318
107
  )}
319
108
 
320
- {devSettings && (
321
- <DevSettingsSection
322
- enabled={devSettings.enabled}
323
- onAfterClear={devSettings.onAfterClear}
324
- texts={devSettings.texts}
325
- />
326
- )}
109
+ {devSettings && <DevSettingsSection {...devSettings} />}
327
110
 
328
111
  {showFooter && (
329
112
  <SettingsFooter
@@ -337,17 +120,7 @@ export const SettingsContent: React.FC<SettingsContentProps> = ({
337
120
  };
338
121
 
339
122
  const styles = StyleSheet.create({
340
- scrollView: {
341
- flex: 1,
342
- },
343
- scrollContent: {
344
- flexGrow: 1,
345
- },
346
- profileContainer: {
347
- marginBottom: 32,
348
- paddingHorizontal: 0,
349
- },
350
- emptyContainer: {
351
- paddingVertical: 24,
352
- },
123
+ scrollView: { flex: 1 },
124
+ scrollContent: { flexGrow: 1 },
125
+ emptyContainer: { paddingVertical: 24 },
353
126
  });
@@ -0,0 +1,31 @@
1
+ import React, { useMemo } from "react";
2
+ import { SettingsSection } from "../../../components/SettingsSection";
3
+ import type { CustomSettingsSection } from "../../types";
4
+
5
+ interface CustomSettingsListProps {
6
+ customSections?: CustomSettingsSection[];
7
+ }
8
+
9
+ export const CustomSettingsList: React.FC<CustomSettingsListProps> = ({
10
+ customSections = [],
11
+ }) => {
12
+ const sortedSections = useMemo(() => {
13
+ return Array.from(customSections)
14
+ .sort((a, b) => (a.order ?? 999) - (b.order ?? 999));
15
+ }, [customSections]);
16
+
17
+ if (!sortedSections.length) return null;
18
+
19
+ return (
20
+ <>
21
+ {sortedSections.map((section, index) => (
22
+ <SettingsSection
23
+ key={section.id || `custom-${index}`}
24
+ title={section.title}
25
+ >
26
+ {section.content}
27
+ </SettingsSection>
28
+ ))}
29
+ </>
30
+ );
31
+ };
@@ -0,0 +1,55 @@
1
+ import React from "react";
2
+ import { AppearanceSection } from "../../../../domains/appearance/presentation/components/AppearanceSection";
3
+ import { LanguageSection } from "@umituz/react-native-localization";
4
+ import { NotificationsSection } from "@umituz/react-native-notifications";
5
+ import { useLocalization } from "@umituz/react-native-localization";
6
+ import type { NormalizedConfig } from "../../utils/normalizeConfig";
7
+
8
+ interface FeatureSettingsSectionProps {
9
+ normalizedConfig: NormalizedConfig;
10
+ features: any;
11
+ }
12
+
13
+ export const FeatureSettingsSection: React.FC<FeatureSettingsSectionProps> = ({
14
+ normalizedConfig,
15
+ features,
16
+ }) => {
17
+ const { t } = useLocalization();
18
+
19
+ return (
20
+ <>
21
+ {features.appearance && (
22
+ <AppearanceSection
23
+ config={{
24
+ ...normalizedConfig.appearance.config,
25
+ title: t("settings.appearance.title"),
26
+ description: t("settings.appearance.description"),
27
+ }}
28
+ sectionTitle={t("settings.appearance.title")}
29
+ />
30
+ )}
31
+
32
+ {features.language && (
33
+ <LanguageSection
34
+ config={{
35
+ ...normalizedConfig.language.config,
36
+ title: t("settings.languageSelection.title"),
37
+ description:
38
+ normalizedConfig.language.config?.description ||
39
+ t("settings.languageSelection.description"),
40
+ }}
41
+ />
42
+ )}
43
+
44
+ {features.notifications && (
45
+ <NotificationsSection
46
+ config={{
47
+ ...normalizedConfig.notifications.config,
48
+ title: t("settings.notifications.title"),
49
+ description: t("settings.notifications.description"),
50
+ }}
51
+ />
52
+ )}
53
+ </>
54
+ );
55
+ };
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import { AboutSection } from "../../../../domains/about/presentation/components/AboutSection";
3
+ import { LegalSection } from "../../../../domains/legal/presentation/components/LegalSection";
4
+ import { useLocalization } from "@umituz/react-native-localization";
5
+ import type { NormalizedConfig } from "../../utils/normalizeConfig";
6
+
7
+ interface IdentitySettingsSectionProps {
8
+ normalizedConfig: NormalizedConfig;
9
+ features: any;
10
+ }
11
+
12
+ export const IdentitySettingsSection: React.FC<IdentitySettingsSectionProps> = ({
13
+ normalizedConfig,
14
+ features,
15
+ }) => {
16
+ const { t } = useLocalization();
17
+
18
+ return (
19
+ <>
20
+ {features.about && (
21
+ <AboutSection
22
+ config={{
23
+ ...normalizedConfig.about.config,
24
+ title: t("settings.about.title"),
25
+ description: t("settings.about.description"),
26
+ }}
27
+ sectionTitle={t("settings.about.title")}
28
+ />
29
+ )}
30
+
31
+ {features.legal && (
32
+ <LegalSection
33
+ config={{
34
+ ...normalizedConfig.legal.config,
35
+ title: t("settings.legal.title"),
36
+ description: t("settings.legal.description"),
37
+ }}
38
+ sectionTitle={t("settings.legal.title")}
39
+ />
40
+ )}
41
+ </>
42
+ );
43
+ };
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ import { View, StyleSheet } from "react-native";
3
+ import { ProfileSection } from "@umituz/react-native-auth";
4
+ import { useLocalization } from "@umituz/react-native-localization";
5
+
6
+ export interface ProfileSectionLoaderProps {
7
+ userProfile?: {
8
+ displayName?: string;
9
+ userId?: string;
10
+ isAnonymous?: boolean;
11
+ avatarUrl?: string;
12
+ accountSettingsRoute?: string;
13
+ onPress?: () => void;
14
+ };
15
+ }
16
+
17
+
18
+ export const ProfileSectionLoader: React.FC<ProfileSectionLoaderProps> = ({ userProfile }) => {
19
+ const { t } = useLocalization();
20
+
21
+ if (!userProfile) return null;
22
+
23
+ return (
24
+ <View style={styles.profileContainer}>
25
+ <ProfileSection
26
+ profile={{
27
+ displayName: userProfile.displayName || "",
28
+ userId: userProfile.userId,
29
+ isAnonymous: userProfile.isAnonymous ?? true,
30
+ avatarUrl: userProfile.avatarUrl,
31
+ accountSettingsRoute: userProfile.accountSettingsRoute,
32
+ }}
33
+ onPress={userProfile.onPress}
34
+ onSignIn={userProfile.onPress}
35
+ signInText={t("auth.signIn")}
36
+ anonymousText={t("settings.profile.anonymousName")}
37
+ />
38
+ </View>
39
+ );
40
+ };
41
+
42
+ const styles = StyleSheet.create({
43
+ profileContainer: {
44
+ marginBottom: 32,
45
+ paddingHorizontal: 0,
46
+ },
47
+ });
@@ -0,0 +1,84 @@
1
+ import React from "react";
2
+ import { useLocalization } from "@umituz/react-native-localization";
3
+ import { SupportSection } from "../../../../domains/feedback/presentation/components/SupportSection";
4
+ import { FAQSection } from "../../../../domains/faqs/presentation/components/FAQSection";
5
+ import { SettingsSection } from "../../../components/SettingsSection";
6
+ import { SettingItem } from "../../../components/SettingItem";
7
+
8
+ interface SupportSettingsSectionProps {
9
+ features: any;
10
+ normalizedConfig: any;
11
+ }
12
+
13
+ export const SupportSettingsSection: React.FC<SupportSettingsSectionProps> = ({
14
+ features,
15
+ normalizedConfig,
16
+ }) => {
17
+ const { t } = useLocalization();
18
+
19
+ if (!(features.feedback || features.rating || features.faqs)) return null;
20
+
21
+ return (
22
+ <SettingsSection title={t("settings.support.title")}>
23
+ {(features.feedback || features.rating) && (
24
+ <SupportSection
25
+ renderSection={(props: any) => <>{props.children}</>}
26
+ renderItem={(props: any) => <SettingItem {...props} />}
27
+ feedbackConfig={{
28
+ enabled: features.feedback,
29
+ config: {
30
+ ...normalizedConfig.feedback.config,
31
+ title: normalizedConfig.feedback.config?.title || t("settings.feedback.title"),
32
+ description: normalizedConfig.feedback.config?.description || t("settings.feedback.description"),
33
+ }
34
+ }}
35
+ ratingConfig={{
36
+ enabled: features.rating,
37
+ config: {
38
+ ...normalizedConfig.rating.config,
39
+ title: normalizedConfig.rating.config?.title || t("settings.rating.title"),
40
+ description: normalizedConfig.rating.config?.description || t("settings.rating.description"),
41
+ }
42
+ }}
43
+ feedbackModalTexts={{
44
+ title: t("settings.feedback.modal.title"),
45
+ ratingLabel: t("settings.feedback.modal.ratingLabel"),
46
+ descriptionPlaceholder: t("settings.feedback.modal.descriptionPlaceholder"),
47
+ submitButton: t("settings.feedback.modal.submitButton"),
48
+ submittingButton: t("settings.feedback.modal.submittingButton"),
49
+ feedbackTypes: [
50
+ { type: 'general', label: t("settings.feedback.types.general") },
51
+ { type: 'bug_report', label: t("settings.feedback.types.bugReport") },
52
+ { type: 'feature_request', label: t("settings.feedback.types.featureRequest") },
53
+ { type: 'improvement', label: t("settings.feedback.types.improvement") },
54
+ { type: 'other', label: t("settings.feedback.types.other") },
55
+ ],
56
+ defaultTitle: (type) => {
57
+ const titles: Record<string, string> = {
58
+ general: t("settings.feedback.types.general"),
59
+ bug_report: t("settings.feedback.types.bugReport"),
60
+ feature_request: t("settings.feedback.types.featureRequest"),
61
+ improvement: t("settings.feedback.types.improvement"),
62
+ other: t("settings.feedback.types.other"),
63
+ };
64
+ return titles[type] || type;
65
+ },
66
+ }}
67
+ />
68
+ )}
69
+
70
+ {features.faqs && (
71
+ <FAQSection
72
+ renderSection={(props: any) => <>{props.children}</>}
73
+ renderItem={(props: any) => <SettingItem {...props} />}
74
+ config={{
75
+ enabled: features.faqs,
76
+ ...normalizedConfig.faqs.config,
77
+ title: normalizedConfig.faqs.config?.title || t("settings.faqs.title"),
78
+ description: normalizedConfig.faqs.config?.description || t("settings.faqs.description"),
79
+ }}
80
+ />
81
+ )}
82
+ </SettingsSection>
83
+ );
84
+ };
@@ -6,20 +6,6 @@
6
6
  import { useMemo } from "react";
7
7
  import type { NormalizedConfig } from "../utils/normalizeConfig";
8
8
 
9
- // Optional notification service
10
- let notificationService: {
11
- hasPermissions?: () => Promise<boolean>;
12
- requestPermissions?: () => Promise<void>;
13
- } | null = null;
14
- try {
15
- // eslint-disable-next-line @typescript-eslint/no-require-imports
16
- const module = require("@umituz/react-native-notifications");
17
- if (module?.notificationService && typeof module.notificationService === 'object') {
18
- notificationService = module.notificationService;
19
- }
20
- } catch {
21
- // Package not available
22
- }
23
9
 
24
10
  /**
25
11
  * Check if navigation screen exists
@@ -75,8 +61,7 @@ export function useFeatureDetection(
75
61
  faqs,
76
62
  } = normalizedConfig;
77
63
 
78
- const notificationServiceAvailable =
79
- options?.notificationServiceAvailable ?? notificationService !== null;
64
+ const notificationServiceAvailable = !!options?.notificationServiceAvailable;
80
65
 
81
66
  return {
82
67
  appearance:
@@ -248,3 +248,21 @@ export interface RatingConfig {
248
248
  /** Custom handler for rating action (e.g. open store review) */
249
249
  onRate?: () => void;
250
250
  }
251
+
252
+ /**
253
+ * Cloud Sync Settings Configuration
254
+ */
255
+ export interface CloudSyncConfig {
256
+ /** Enable cloud sync feature */
257
+ enabled?: FeatureVisibility;
258
+ /** Custom title for the sync section */
259
+ title?: string;
260
+ /** Custom description for the sync toggle */
261
+ description?: string;
262
+ /** Custom icon name (Ionicons) */
263
+ icon?: string;
264
+ /** Custom section title for grouping */
265
+ sectionTitle?: string;
266
+ /** Firestore collection name */
267
+ collectionName?: string;
268
+ }
@@ -16,6 +16,7 @@ import type {
16
16
  FeedbackConfig,
17
17
  RatingConfig,
18
18
  FAQConfig,
19
+ CloudSyncConfig,
19
20
  } from "./FeatureConfig";
20
21
 
21
22
  /**
@@ -115,6 +116,12 @@ export interface SettingsConfig {
115
116
  */
116
117
  faqs?: FeatureVisibility | FAQConfig;
117
118
 
119
+ /**
120
+ * Cloud sync settings configuration
121
+ * @default false
122
+ */
123
+ cloudSync?: FeatureVisibility | CloudSyncConfig;
124
+
118
125
  /**
119
126
  * Custom empty state text when no settings are available
120
127
  */