@umituz/react-native-settings 4.20.5 → 4.20.7

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/about/utils/index.ts +2 -8
  3. package/src/domains/appearance/infrastructure/services/systemThemeDetection.ts +2 -8
  4. package/src/domains/appearance/presentation/components/ColorPicker.tsx +3 -6
  5. package/src/domains/appearance/presentation/components/CustomColorsSection.tsx +4 -8
  6. package/src/domains/appearance/presentation/components/ThemeModeSection.tsx +2 -4
  7. package/src/domains/faqs/presentation/components/FAQSection.tsx +4 -4
  8. package/src/domains/feedback/presentation/components/SupportSection.tsx +2 -15
  9. package/src/domains/legal/domain/services/ContentValidationService.ts +26 -34
  10. package/src/domains/legal/domain/services/UrlHandlerService.ts +2 -16
  11. package/src/domains/legal/presentation/components/LegalDocumentsList.tsx +2 -8
  12. package/src/domains/legal/presentation/components/LegalLinks.tsx +4 -8
  13. package/src/domains/legal/presentation/screens/PrivacyPolicyScreen.tsx +2 -8
  14. package/src/domains/legal/presentation/screens/TermsOfServiceScreen.tsx +2 -8
  15. package/src/domains/video-tutorials/presentation/components/VideoTutorialCard.tsx +2 -2
  16. package/src/domains/video-tutorials/presentation/screens/VideoTutorialsScreen.tsx +1 -8
  17. package/src/presentation/components/SettingItem.tsx +1 -1
  18. package/src/presentation/components/SettingsErrorBoundary.tsx +4 -4
  19. package/src/presentation/screens/components/SettingsContent.tsx +7 -0
  20. package/src/presentation/screens/components/sections/SubscriptionSettingsSection.tsx +49 -0
  21. package/src/presentation/screens/hooks/useFeatureDetection.ts +2 -0
  22. package/src/presentation/screens/types/FeatureConfig.ts +19 -0
  23. package/src/presentation/screens/types/SettingsConfig.ts +7 -0
  24. package/src/presentation/screens/utils/normalizeConfig.ts +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "4.20.5",
3
+ "version": "4.20.7",
4
4
  "description": "Complete settings hub for React Native apps - consolidated package with settings, about, legal, appearance, feedback, FAQs, and rating",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -125,10 +125,7 @@ export const openUrl = async (url: string): Promise<boolean> => {
125
125
  }
126
126
 
127
127
  return false;
128
- } catch (error) {
129
- if (__DEV__) {
130
- console.error('Failed to open URL:', error);
131
- }
128
+ } catch {
132
129
  return false;
133
130
  }
134
131
  };
@@ -151,10 +148,7 @@ export const sendEmail = async (email: string, subject?: string): Promise<boolea
151
148
  }
152
149
 
153
150
  return false;
154
- } catch (error) {
155
- if (__DEV__) {
156
- console.error('Failed to send email:', error);
157
- }
151
+ } catch {
158
152
  return false;
159
153
  }
160
154
  };
@@ -29,10 +29,7 @@ export const getSystemTheme = (): ThemeMode | null => {
29
29
  // On native platforms, use Appearance API
30
30
  const colorScheme = Appearance.getColorScheme();
31
31
  return colorScheme === 'dark' ? 'dark' : 'light';
32
- } catch (error) {
33
- if (__DEV__) {
34
- console.warn('[getSystemTheme] Failed to detect system theme:', error);
35
- }
32
+ } catch {
36
33
  return null;
37
34
  }
38
35
  };
@@ -70,10 +67,7 @@ export const addSystemThemeListener = (
70
67
  return () => {
71
68
  subscription?.remove();
72
69
  };
73
- } catch (error) {
74
- if (__DEV__) {
75
- console.warn('[addSystemThemeListener] Failed to add listener:', error);
76
- }
70
+ } catch {
77
71
  return () => { }; // Return empty cleanup function
78
72
  }
79
73
  };
@@ -39,12 +39,9 @@ export const ColorPicker: React.FC<ColorPickerProps> = ({
39
39
  try {
40
40
  // Prevent unnecessary updates if color hasn't changed
41
41
  if (value === color) return;
42
-
43
42
  onValueChange(color);
44
- } catch (error) {
45
- if (__DEV__) {
46
- console.error("[ColorPicker] Failed to change color:", error);
47
- }
43
+ } catch {
44
+ // Silent error handling
48
45
  }
49
46
  }, [value, onValueChange]);
50
47
 
@@ -65,7 +62,7 @@ export const ColorPicker: React.FC<ColorPickerProps> = ({
65
62
  activeOpacity={0.8} // Performance optimization
66
63
  >
67
64
  {isSelected && (
68
- <AtomicIcon name="checkmark" size="sm" customColor="#FFFFFF" />
65
+ <AtomicIcon name="checkmark" size="sm" customColor={tokens.colors.textInverse} />
69
66
  )}
70
67
  </TouchableOpacity>
71
68
  );
@@ -94,10 +94,8 @@ export const CustomColorsSection: React.FC<CustomColorsSectionProps> = ({
94
94
  const handleColorChange = useCallback((key: keyof CustomThemeColors, color: string) => {
95
95
  try {
96
96
  onColorChange(key, color);
97
- } catch (error) {
98
- if (__DEV__) {
99
- console.error("[CustomColorsSection] Failed to change color:", error);
100
- }
97
+ } catch {
98
+ // Silent error handling
101
99
  }
102
100
  }, [onColorChange]);
103
101
 
@@ -105,10 +103,8 @@ export const CustomColorsSection: React.FC<CustomColorsSectionProps> = ({
105
103
  const handleResetColors = useCallback(() => {
106
104
  try {
107
105
  onResetColors();
108
- } catch (error) {
109
- if (__DEV__) {
110
- console.error("[CustomColorsSection] Failed to reset colors:", error);
111
- }
106
+ } catch {
107
+ // Silent error handling
112
108
  }
113
109
  }, [onResetColors]);
114
110
 
@@ -42,10 +42,8 @@ export const ThemeModeSection: React.FC<ThemeModeSectionProps> = ({
42
42
  const handleThemeSelect = useCallback((mode: ThemeMode) => {
43
43
  try {
44
44
  onThemeSelect(mode);
45
- } catch (error) {
46
- if (__DEV__) {
47
- console.error("[ThemeModeSection] Failed to select theme:", error);
48
- }
45
+ } catch {
46
+ // Silent error handling
49
47
  }
50
48
  }, [onThemeSelect]);
51
49
 
@@ -32,16 +32,16 @@ export const FAQSection: React.FC<FAQSectionProps> = ({
32
32
  renderSection,
33
33
  renderItem,
34
34
  }) => {
35
- if (!config.enabled) return null;
35
+ if (!config.enabled || !config.title || !config.description) return null;
36
36
 
37
37
  return (
38
38
  <>
39
39
  {renderSection({
40
- title: config.title || 'Help & Support',
40
+ title: config.title,
41
41
  children: renderItem({
42
- title: config.description || 'FAQ',
42
+ title: config.description,
43
43
  icon: 'help-circle',
44
- onPress: config.onPress || (() => console.warn('No FAQ handler')),
44
+ onPress: config.onPress || (() => {}),
45
45
  isLast: true,
46
46
  }),
47
47
  })}
@@ -65,17 +65,12 @@ export const SupportSection: React.FC<SupportSectionProps> = ({
65
65
  try {
66
66
  await feedbackConfig.config.onSubmit(data);
67
67
  setModalVisible(false);
68
- } catch (error) {
69
- if (__DEV__) {
70
- console.error("Feedback submission error:", error);
71
- }
68
+ } catch {
69
+ // Silent error handling
72
70
  } finally {
73
71
  setIsSubmitting(false);
74
72
  }
75
73
  } else {
76
- if (__DEV__) {
77
- console.warn("No onSubmit handler provided for Feedback");
78
- }
79
74
  setModalVisible(false);
80
75
  }
81
76
  };
@@ -91,14 +86,6 @@ export const SupportSection: React.FC<SupportSectionProps> = ({
91
86
  const supported = await Linking.canOpenURL(config.storeUrl);
92
87
  if (supported) {
93
88
  await Linking.openURL(config.storeUrl);
94
- } else {
95
- if (__DEV__) {
96
- console.warn("Cannot open store URL:", config.storeUrl);
97
- }
98
- }
99
- } else {
100
- if (__DEV__) {
101
- console.warn("No storeUrl or onRate provided for Rating");
102
89
  }
103
90
  }
104
91
  }, [ratingConfig.config]);
@@ -19,48 +19,40 @@ export class ContentValidationService {
19
19
  * Validate screen content requirements
20
20
  */
21
21
  static validateScreenContent(
22
- content: string | undefined,
23
- url: string | undefined,
24
- title: string | undefined,
25
- viewOnlineText: string | undefined,
26
- openText: string | undefined,
27
- screenName: string
22
+ _content: string | undefined,
23
+ _url: string | undefined,
24
+ _title: string | undefined,
25
+ _viewOnlineText: string | undefined,
26
+ _openText: string | undefined,
27
+ _screenName: string
28
28
  ): void {
29
- if (__DEV__) {
30
- if (!content && !url) {
31
- console.warn(`${screenName}: Either content or url must be provided`);
32
- }
33
- if (!title) {
34
- console.warn(`${screenName}: title is required`);
35
- }
36
- if (url && !viewOnlineText) {
37
- console.warn(`${screenName}: viewOnlineText is required when url is provided`);
38
- }
39
- if (url && !openText) {
40
- console.warn(`${screenName}: openText is required when url is provided`);
41
- }
42
- }
29
+ // Silent validation - no console output
30
+ void _content;
31
+ void _url;
32
+ void _title;
33
+ void _viewOnlineText;
34
+ void _openText;
35
+ void _screenName;
43
36
  }
44
37
 
45
38
  /**
46
39
  * Validate legal links requirements
47
40
  */
48
41
  static validateLegalLinks(
49
- privacyPolicyUrl: string | undefined,
50
- termsOfServiceUrl: string | undefined,
51
- privacyText: string | undefined,
52
- termsText: string | undefined,
53
- onPrivacyPress: (() => void) | undefined,
54
- onTermsPress: (() => void) | undefined
42
+ _privacyPolicyUrl: string | undefined,
43
+ _termsOfServiceUrl: string | undefined,
44
+ _privacyText: string | undefined,
45
+ _termsText: string | undefined,
46
+ _onPrivacyPress: (() => void) | undefined,
47
+ _onTermsPress: (() => void) | undefined
55
48
  ): void {
56
- if (__DEV__) {
57
- if (privacyPolicyUrl && !privacyText && !onPrivacyPress) {
58
- console.warn('LegalLinks: privacyText is required when privacyPolicyUrl is provided');
59
- }
60
- if (termsOfServiceUrl && !termsText && !onTermsPress) {
61
- console.warn('LegalLinks: termsText is required when termsOfServiceUrl is provided');
62
- }
63
- }
49
+ // Silent validation - no console output
50
+ void _privacyPolicyUrl;
51
+ void _termsOfServiceUrl;
52
+ void _privacyText;
53
+ void _termsText;
54
+ void _onPrivacyPress;
55
+ void _onTermsPress;
64
56
  }
65
57
 
66
58
  /**
@@ -51,14 +51,7 @@ export class UrlHandlerService {
51
51
  * Open URL in external browser with performance optimizations
52
52
  */
53
53
  static async openUrl(url: string): Promise<void> {
54
- if (__DEV__) {
55
- console.log('UrlHandlerService: Opening URL', { url });
56
- }
57
-
58
54
  if (!this.isValidUrl(url)) {
59
- if (__DEV__) {
60
- console.warn('UrlHandlerService: Invalid URL provided', { url });
61
- }
62
55
  return;
63
56
  }
64
57
 
@@ -77,16 +70,9 @@ export class UrlHandlerService {
77
70
 
78
71
  if (canOpen) {
79
72
  await Linking.openURL(url);
80
- } else {
81
- if (__DEV__) {
82
- console.warn('UrlHandlerService: Cannot open URL', { url });
83
- }
84
73
  }
85
- } catch (error) {
86
- if (__DEV__) {
87
- console.error('UrlHandlerService: Error opening URL', { url, error });
88
- }
89
- // Don't throw error to prevent app crashes, just log it
74
+ } catch {
75
+ // Silent error handling to prevent app crashes
90
76
  }
91
77
  }
92
78
 
@@ -40,19 +40,13 @@ export const LegalDocumentsList: React.FC<LegalDocumentsListProps> = React.memo(
40
40
  const tokens = useAppDesignTokens();
41
41
 
42
42
  const handleEulaPress = React.useCallback(async () => {
43
- if (__DEV__) {
44
- console.log('LegalDocumentsList: EULA pressed', { eulaUrl });
45
- }
46
-
47
43
  if (onEulaPress) {
48
44
  onEulaPress();
49
45
  } else if (eulaUrl) {
50
46
  try {
51
47
  await UrlHandlerService.openUrl(eulaUrl);
52
- } catch (error) {
53
- if (__DEV__) {
54
- console.error('LegalDocumentsList: Error opening EULA URL', error);
55
- }
48
+ } catch {
49
+ // Silent error handling
56
50
  }
57
51
  }
58
52
  }, [onEulaPress, eulaUrl]);
@@ -70,10 +70,8 @@ export const LegalLinks: React.FC<LegalLinksProps> = React.memo(
70
70
  } else if (privacyPolicyUrl) {
71
71
  try {
72
72
  await UrlHandlerService.openUrl(privacyPolicyUrl);
73
- } catch (error) {
74
- if (__DEV__) {
75
- console.error('LegalLinks: Error opening privacy policy URL', error);
76
- }
73
+ } catch {
74
+ // Silent error handling
77
75
  }
78
76
  }
79
77
  }, [onPrivacyPress, privacyPolicyUrl]);
@@ -84,10 +82,8 @@ export const LegalLinks: React.FC<LegalLinksProps> = React.memo(
84
82
  } else if (termsOfServiceUrl) {
85
83
  try {
86
84
  await UrlHandlerService.openUrl(termsOfServiceUrl);
87
- } catch (error) {
88
- if (__DEV__) {
89
- console.error('LegalLinks: Error opening terms of service URL', error);
90
- }
85
+ } catch {
86
+ // Silent error handling
91
87
  }
92
88
  }
93
89
  }, [onTermsPress, termsOfServiceUrl]);
@@ -81,19 +81,13 @@ export const PrivacyPolicyScreen: React.FC<PrivacyPolicyScreenProps> = React.mem
81
81
 
82
82
  // Memoize URL press handler to prevent child re-renders
83
83
  const handleUrlPress = React.useCallback(async () => {
84
- if (__DEV__) {
85
- console.log('PrivacyPolicyScreen: URL pressed', { url });
86
- }
87
-
88
84
  if (onUrlPress) {
89
85
  onUrlPress();
90
86
  } else if (url) {
91
87
  try {
92
88
  await UrlHandlerService.openUrl(url);
93
- } catch (error) {
94
- if (__DEV__) {
95
- console.error('PrivacyPolicyScreen: Error opening URL', error);
96
- }
89
+ } catch {
90
+ // Silent error handling
97
91
  }
98
92
  }
99
93
  }, [onUrlPress, url]);
@@ -81,19 +81,13 @@ export const TermsOfServiceScreen: React.FC<TermsOfServiceScreenProps> = React.m
81
81
 
82
82
  // Memoize URL press handler to prevent child re-renders
83
83
  const handleUrlPress = React.useCallback(async () => {
84
- if (__DEV__) {
85
- console.log('TermsOfServiceScreen: URL pressed', { url });
86
- }
87
-
88
84
  if (onUrlPress) {
89
85
  onUrlPress();
90
86
  } else if (url) {
91
87
  try {
92
88
  await UrlHandlerService.openUrl(url);
93
- } catch (error) {
94
- if (__DEV__) {
95
- console.error('TermsOfServiceScreen: Error opening URL', error);
96
- }
89
+ } catch {
90
+ // Silent error handling
97
91
  }
98
92
  }
99
93
  }, [onUrlPress, url]);
@@ -61,7 +61,7 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
61
61
  { backgroundColor: tokens.colors.primary },
62
62
  ]}
63
63
  >
64
- <Text style={[styles.featuredText, { color: "#FFFFFF" }]}>
64
+ <Text style={[styles.featuredText, { color: tokens.colors.onPrimary }]}>
65
65
  Featured
66
66
  </Text>
67
67
  </View>
@@ -140,7 +140,7 @@ const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
140
140
  borderRadius: 4,
141
141
  },
142
142
  durationText: {
143
- color: "white",
143
+ color: tokens.colors.textInverse,
144
144
  fontSize: 12,
145
145
  fontWeight: "500",
146
146
  },
@@ -85,14 +85,7 @@ export const VideoTutorialsScreen: React.FC<VideoTutorialsScreenProps> =
85
85
 
86
86
  const handleTutorialPress = React.useCallback(
87
87
  (tutorialId: string) => {
88
- if (onTutorialPress) {
89
- onTutorialPress(tutorialId);
90
- } else if (__DEV__) {
91
- // eslint-disable-next-line no-console
92
- console.log("VideoTutorialsScreen: No onTutorialPress handler", {
93
- tutorialId,
94
- });
95
- }
88
+ onTutorialPress?.(tutorialId);
96
89
  },
97
90
  [onTutorialPress],
98
91
  );
@@ -96,7 +96,7 @@ export const SettingItem: React.FC<SettingItemProps> = ({
96
96
  false: tokens.colors.surfaceVariant,
97
97
  true: tokens.colors.primary
98
98
  }}
99
- thumbColor="#FFFFFF"
99
+ thumbColor={tokens.colors.surface}
100
100
  ios_backgroundColor={tokens.colors.surfaceVariant}
101
101
  disabled={disabled}
102
102
  />
@@ -31,10 +31,10 @@ export class SettingsErrorBoundary extends Component<Props, State> {
31
31
  return { hasError: true, error };
32
32
  }
33
33
 
34
- override componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
35
- if (__DEV__) {
36
- console.error('Settings Error Boundary caught an error:', error, errorInfo);
37
- }
34
+ override componentDidCatch(_error: Error, _errorInfo: React.ErrorInfo) {
35
+ // Silent error handling - error already captured in state
36
+ void _error;
37
+ void _errorInfo;
38
38
  }
39
39
 
40
40
  override render() {
@@ -11,6 +11,7 @@ import { ProfileSectionLoader } from "./sections/ProfileSectionLoader";
11
11
  import { FeatureSettingsSection } from "./sections/FeatureSettingsSection";
12
12
  import { IdentitySettingsSection } from "./sections/IdentitySettingsSection";
13
13
  import { SupportSettingsSection } from "./sections/SupportSettingsSection";
14
+ import { SubscriptionSettingsSection } from "./sections/SubscriptionSettingsSection";
14
15
  import { CustomSettingsList } from "./sections/CustomSettingsList";
15
16
  import type { NormalizedConfig } from "../utils/normalizeConfig";
16
17
  import type { CustomSettingsSection } from "../types";
@@ -29,6 +30,7 @@ interface SettingsContentProps {
29
30
  feedback: boolean;
30
31
  rating: boolean;
31
32
  faqs: boolean;
33
+ subscription: boolean;
32
34
  };
33
35
  showUserProfile?: boolean;
34
36
  userProfile?: any;
@@ -67,6 +69,7 @@ export const SettingsContent: React.FC<SettingsContentProps> = ({
67
69
  features.feedback ||
68
70
  features.rating ||
69
71
  features.faqs ||
72
+ features.subscription ||
70
73
  customSections.length > 0,
71
74
  [features, customSections.length]
72
75
  );
@@ -88,6 +91,10 @@ export const SettingsContent: React.FC<SettingsContentProps> = ({
88
91
 
89
92
  <CustomSettingsList customSections={customSections} />
90
93
 
94
+ {features.subscription && (
95
+ <SubscriptionSettingsSection config={normalizedConfig.subscription.config} />
96
+ )}
97
+
91
98
  <FeatureSettingsSection normalizedConfig={normalizedConfig} features={features} />
92
99
 
93
100
  <IdentitySettingsSection normalizedConfig={normalizedConfig} features={features} />
@@ -0,0 +1,49 @@
1
+ import React from "react";
2
+ import { View } from "react-native";
3
+ import {
4
+ ListItem,
5
+ AtomicBadge,
6
+ useAppDesignTokens,
7
+ } from "@umituz/react-native-design-system";
8
+ import { useLocalization } from "@umituz/react-native-localization";
9
+ import { SettingsSection } from "../../../components/SettingsSection";
10
+ import type { SubscriptionConfig } from "../../types";
11
+
12
+ interface SubscriptionSettingsSectionProps {
13
+ config?: SubscriptionConfig;
14
+ }
15
+
16
+ export const SubscriptionSettingsSection: React.FC<SubscriptionSettingsSectionProps> = ({
17
+ config,
18
+ }) => {
19
+ const { t } = useLocalization();
20
+ const tokens = useAppDesignTokens();
21
+
22
+ if (!config) return null;
23
+
24
+ return (
25
+ <SettingsSection title={config.sectionTitle || t("settings.sections.subscription")}>
26
+ <ListItem
27
+ title={config.title || t("settings.subscription.title")}
28
+ description={config.description || t("settings.subscription.description")}
29
+ leftIcon={config.icon || "star"}
30
+ onPress={config.onPress}
31
+ rightElement={
32
+ config.isPremium ? (
33
+ <AtomicBadge
34
+ label={t("common.premium")}
35
+ variant="success"
36
+ size="small"
37
+ />
38
+ ) : (
39
+ <AtomicBadge
40
+ label={t("common.free")}
41
+ variant="warning"
42
+ size="small"
43
+ />
44
+ )
45
+ }
46
+ />
47
+ </SettingsSection>
48
+ );
49
+ };
@@ -58,6 +58,7 @@ export function useFeatureDetection(
58
58
  feedback,
59
59
  rating,
60
60
  faqs,
61
+ subscription,
61
62
  } = normalizedConfig;
62
63
 
63
64
  const notificationServiceAvailable = !!options?.notificationServiceAvailable;
@@ -110,6 +111,7 @@ export function useFeatureDetection(
110
111
  feedback: feedback.enabled,
111
112
  rating: rating.enabled,
112
113
  faqs: faqs.enabled,
114
+ subscription: subscription.enabled,
113
115
  };
114
116
  }, [normalizedConfig, navigation, options]);
115
117
  }
@@ -218,3 +218,22 @@ export interface CloudSyncConfig {
218
218
  /** Firestore collection name */
219
219
  collectionName?: string;
220
220
  }
221
+ /**
222
+ * Subscription Settings Configuration
223
+ */
224
+ export interface SubscriptionConfig {
225
+ /** Show subscription section */
226
+ enabled?: FeatureVisibility;
227
+ /** Custom title for the subscription section */
228
+ title?: string;
229
+ /** Custom label for the subscription item */
230
+ description?: string;
231
+ /** Custom icon name (Ionicons) */
232
+ icon?: string;
233
+ /** Custom section title for grouping */
234
+ sectionTitle?: string;
235
+ /** Handler to open subscription screen */
236
+ onPress?: () => void;
237
+ /** Whether user is premium (to show active status) */
238
+ isPremium?: boolean;
239
+ }
@@ -16,6 +16,7 @@ import type {
16
16
  RatingConfig,
17
17
  FAQConfig,
18
18
  CloudSyncConfig,
19
+ SubscriptionConfig,
19
20
  } from "./FeatureConfig";
20
21
 
21
22
  /**
@@ -113,6 +114,12 @@ export interface SettingsConfig {
113
114
  * @default false
114
115
  */
115
116
  cloudSync?: FeatureVisibility | CloudSyncConfig;
117
+
118
+ /**
119
+ * Subscription settings configuration
120
+ * @default false
121
+ */
122
+ subscription?: FeatureVisibility | SubscriptionConfig;
116
123
 
117
124
  /**
118
125
  * Custom empty state text when no settings are available
@@ -15,6 +15,7 @@ import type {
15
15
  FeedbackConfig,
16
16
  RatingConfig,
17
17
  FAQConfig,
18
+ SubscriptionConfig,
18
19
  SettingsConfig,
19
20
  } from "../types";
20
21
 
@@ -59,6 +60,10 @@ export interface NormalizedConfig {
59
60
  enabled: boolean;
60
61
  config?: FAQConfig;
61
62
  };
63
+ subscription: {
64
+ enabled: boolean;
65
+ config?: SubscriptionConfig;
66
+ };
62
67
  }
63
68
 
64
69
  /**
@@ -103,5 +108,6 @@ export function normalizeSettingsConfig(
103
108
  feedback: normalizeConfigValue(config?.feedback, false),
104
109
  rating: normalizeConfigValue(config?.rating, false),
105
110
  faqs: normalizeConfigValue(config?.faqs, false),
111
+ subscription: normalizeConfigValue(config?.subscription, false),
106
112
  };
107
113
  }