@umituz/react-native-settings 4.17.27 → 4.17.31

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 (44) hide show
  1. package/package.json +15 -4
  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/faqs/presentation/screens/FAQScreen.tsx +1 -1
  15. package/src/domains/feedback/presentation/components/FeedbackModal.tsx +11 -15
  16. package/src/domains/feedback/presentation/components/SupportSection.tsx +2 -2
  17. package/src/domains/legal/presentation/components/LegalItem.tsx +13 -129
  18. package/src/index.ts +19 -9
  19. package/src/infrastructure/repositories/SettingsRepository.ts +105 -0
  20. package/src/infrastructure/services/SettingsService.ts +47 -0
  21. package/src/presentation/components/SettingItem.tsx +77 -129
  22. package/src/presentation/components/SettingsFooter.tsx +9 -25
  23. package/src/presentation/components/SettingsSection.tsx +9 -20
  24. package/src/presentation/hooks/mutations/useSettingsMutations.ts +58 -0
  25. package/src/presentation/hooks/queries/useSettingsQuery.ts +27 -0
  26. package/src/presentation/hooks/useSettings.ts +45 -0
  27. package/src/presentation/screens/components/SettingsContent.tsx +20 -247
  28. package/src/presentation/screens/components/sections/CustomSettingsList.tsx +31 -0
  29. package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +68 -0
  30. package/src/presentation/screens/components/sections/IdentitySettingsSection.tsx +43 -0
  31. package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +47 -0
  32. package/src/presentation/screens/components/sections/SubscriptionSettingsItem.tsx +157 -0
  33. package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +84 -0
  34. package/src/presentation/screens/hooks/useFeatureDetection.ts +1 -16
  35. package/src/presentation/screens/types/FeatureConfig.ts +35 -10
  36. package/src/presentation/screens/types/SettingsConfig.ts +7 -0
  37. package/src/presentation/screens/types/index.ts +1 -0
  38. package/src/domains/appearance/infrastructure/services/appearanceService.ts +0 -301
  39. package/src/domains/appearance/infrastructure/storage/appearanceStorage.ts +0 -120
  40. package/src/domains/appearance/infrastructure/stores/appearanceStore.ts +0 -132
  41. package/src/infrastructure/storage/SettingsStore.ts +0 -189
  42. package/src/infrastructure/storage/__tests__/SettingsStore.test.tsx +0 -302
  43. package/src/presentation/components/CloudSyncSetting.tsx +0 -58
  44. /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,68 @@
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 { SubscriptionSettingsItem } from "./SubscriptionSettingsItem";
7
+ import type { NormalizedConfig } from "../../utils/normalizeConfig";
8
+
9
+ interface FeatureSettingsSectionProps {
10
+ normalizedConfig: NormalizedConfig;
11
+ features: {
12
+ appearance: boolean;
13
+ language: boolean;
14
+ notifications: boolean;
15
+ subscription: boolean;
16
+ };
17
+ }
18
+
19
+ export const FeatureSettingsSection: React.FC<FeatureSettingsSectionProps> = ({
20
+ normalizedConfig,
21
+ features,
22
+ }) => {
23
+ const { t } = useLocalization();
24
+
25
+ return (
26
+ <>
27
+ {features.appearance && (
28
+ <AppearanceSection
29
+ config={{
30
+ ...normalizedConfig.appearance.config,
31
+ title: t("settings.appearance.title"),
32
+ description: t("settings.appearance.description"),
33
+ }}
34
+ sectionTitle={t("settings.appearance.title")}
35
+ />
36
+ )}
37
+
38
+ {features.language && (
39
+ <LanguageSection
40
+ config={{
41
+ ...normalizedConfig.language.config,
42
+ title: t("settings.languageSelection.title"),
43
+ description:
44
+ normalizedConfig.language.config?.description ||
45
+ t("settings.languageSelection.description"),
46
+ }}
47
+ />
48
+ )}
49
+
50
+ {features.notifications && (
51
+ <NotificationsSection
52
+ config={{
53
+ ...normalizedConfig.notifications.config,
54
+ title: t("settings.notifications.title"),
55
+ description: t("settings.notifications.description"),
56
+ }}
57
+ />
58
+ )}
59
+
60
+ {features.subscription && normalizedConfig.subscription.config?.settingsItem && (
61
+ <SubscriptionSettingsItem
62
+ config={normalizedConfig.subscription.config.settingsItem}
63
+ sectionTitle={t("settings.subscription.title")}
64
+ />
65
+ )}
66
+ </>
67
+ );
68
+ };
@@ -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,157 @@
1
+ /**
2
+ * Subscription Settings Item
3
+ * Settings-style item for subscription/premium status display
4
+ * Follows same visual pattern as other settings items
5
+ */
6
+
7
+ import React from "react";
8
+ import { View, Pressable, StyleSheet } from "react-native";
9
+ import {
10
+ useResponsiveDesignTokens,
11
+ AtomicIcon,
12
+ AtomicText,
13
+ } from "@umituz/react-native-design-system";
14
+
15
+ export interface SubscriptionSettingsItemConfig {
16
+ title: string;
17
+ description?: string;
18
+ isPremium: boolean;
19
+ statusLabel: string;
20
+ icon?: string;
21
+ onPress?: () => void;
22
+ }
23
+
24
+ export interface SubscriptionSettingsItemProps {
25
+ config: SubscriptionSettingsItemConfig;
26
+ sectionTitle?: string;
27
+ }
28
+
29
+ export const SubscriptionSettingsItem: React.FC<SubscriptionSettingsItemProps> = ({
30
+ config,
31
+ sectionTitle,
32
+ }) => {
33
+ const tokens = useResponsiveDesignTokens();
34
+ const colors = tokens.colors;
35
+
36
+ const { title, description, isPremium, statusLabel, icon, onPress } = config;
37
+ const displaySectionTitle = sectionTitle || title;
38
+
39
+ if (!title) return null;
40
+
41
+ return (
42
+ <View style={[styles.sectionContainer, { backgroundColor: colors.surface }]}>
43
+ {!!displaySectionTitle && (
44
+ <View style={styles.headerContainer}>
45
+ <AtomicText type="titleMedium" color="primary">
46
+ {displaySectionTitle}
47
+ </AtomicText>
48
+ </View>
49
+ )}
50
+ <Pressable
51
+ style={({ pressed }) => [
52
+ styles.itemContainer,
53
+ { backgroundColor: pressed ? `${colors.primary}08` : "transparent" },
54
+ ]}
55
+ onPress={onPress}
56
+ >
57
+ <View style={styles.content}>
58
+ <View
59
+ style={[
60
+ styles.iconContainer,
61
+ { backgroundColor: isPremium ? `${colors.primary}15` : `${colors.textTertiary}15` },
62
+ ]}
63
+ >
64
+ <AtomicIcon
65
+ name={icon || "diamond"}
66
+ size="lg"
67
+ color={isPremium ? "primary" : "secondary"}
68
+ />
69
+ </View>
70
+ <View style={styles.textContainer}>
71
+ <View style={styles.titleRow}>
72
+ <AtomicText
73
+ type="bodyLarge"
74
+ color="primary"
75
+ numberOfLines={1}
76
+ style={styles.title}
77
+ >
78
+ {title}
79
+ </AtomicText>
80
+ <View
81
+ style={[
82
+ styles.statusBadge,
83
+ { backgroundColor: isPremium ? colors.success : colors.textTertiary },
84
+ ]}
85
+ >
86
+ <AtomicText type="labelSmall" style={styles.statusText}>
87
+ {statusLabel}
88
+ </AtomicText>
89
+ </View>
90
+ </View>
91
+ {!!description && (
92
+ <AtomicText type="bodyMedium" color="secondary" numberOfLines={2}>
93
+ {description}
94
+ </AtomicText>
95
+ )}
96
+ </View>
97
+ <AtomicIcon name="chevron-forward" size="md" color="secondary" />
98
+ </View>
99
+ </Pressable>
100
+ </View>
101
+ );
102
+ };
103
+
104
+ const styles = StyleSheet.create({
105
+ sectionContainer: {
106
+ marginBottom: 16,
107
+ borderRadius: 12,
108
+ overflow: "hidden",
109
+ },
110
+ headerContainer: {
111
+ paddingHorizontal: 16,
112
+ paddingTop: 16,
113
+ paddingBottom: 8,
114
+ },
115
+ itemContainer: {
116
+ flexDirection: "row",
117
+ alignItems: "center",
118
+ paddingHorizontal: 16,
119
+ paddingVertical: 16,
120
+ minHeight: 72,
121
+ },
122
+ content: {
123
+ flex: 1,
124
+ flexDirection: "row",
125
+ alignItems: "center",
126
+ },
127
+ iconContainer: {
128
+ width: 48,
129
+ height: 48,
130
+ borderRadius: 12,
131
+ justifyContent: "center",
132
+ alignItems: "center",
133
+ marginRight: 16,
134
+ },
135
+ textContainer: {
136
+ flex: 1,
137
+ marginRight: 8,
138
+ },
139
+ titleRow: {
140
+ flexDirection: "row",
141
+ alignItems: "center",
142
+ marginBottom: 4,
143
+ },
144
+ title: {
145
+ flex: 1,
146
+ },
147
+ statusBadge: {
148
+ paddingHorizontal: 8,
149
+ paddingVertical: 2,
150
+ borderRadius: 4,
151
+ marginLeft: 8,
152
+ },
153
+ statusText: {
154
+ color: "#FFFFFF",
155
+ fontWeight: "600",
156
+ },
157
+ });