@umituz/react-native-settings 4.23.71 → 4.23.73
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.
- package/package.json +1 -1
- package/src/domains/about/presentation/screens/AboutScreen.tsx +10 -173
- package/src/domains/about/presentation/screens/AboutScreenContainer.tsx +109 -0
- package/src/domains/about/presentation/screens/AboutScreenContent.tsx +122 -0
- package/src/domains/dev/presentation/screens/EnvViewerScreen.tsx +51 -50
- package/src/domains/disclaimer/presentation/screens/DisclaimerScreen.tsx +28 -40
- package/src/domains/feedback/presentation/components/FeedbackModal.tsx +32 -43
- package/src/domains/gamification/components/GamificationScreen/GamificationScreen.tsx +122 -0
- package/src/domains/gamification/components/GamificationScreen/GamificationScreenWithConfig.tsx +72 -0
- package/src/domains/gamification/components/GamificationScreen/index.tsx +8 -178
- package/src/domains/gamification/components/index.ts +2 -1
- package/src/domains/legal/presentation/screens/LegalContentScreen.tsx +19 -29
- package/src/domains/notifications/infrastructure/services/NotificationManager.ts +0 -2
- package/src/domains/notifications/infrastructure/services/NotificationService.ts +5 -1
- package/src/index.ts +0 -1
- package/src/infrastructure/utils/index.ts +7 -0
- package/src/infrastructure/utils/memoUtils.ts +159 -0
- package/src/infrastructure/utils/styleUtils.ts +190 -0
- package/src/presentation/screens/SettingsScreen.tsx +0 -5
- package/src/presentation/components/SettingsErrorBoundary/README.md +0 -67
- package/src/presentation/components/SettingsErrorBoundary.tsx +0 -139
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
|
-
import { View, StyleSheet, TouchableOpacity
|
|
8
|
-
import {
|
|
9
|
-
import { useAppDesignTokens, AtomicText, AtomicIcon, BaseModal } from "@umituz/react-native-design-system";
|
|
7
|
+
import { View, StyleSheet, TouchableOpacity } from "react-native";
|
|
8
|
+
import { useAppDesignTokens, AtomicText, AtomicIcon, BaseModal, ScreenLayout } from "@umituz/react-native-design-system";
|
|
10
9
|
import { FeedbackForm } from "./FeedbackForm";
|
|
11
10
|
import type { FeedbackType, FeedbackRating } from "../../domain/entities/FeedbackEntity";
|
|
12
11
|
import type { FeedbackFormProps } from "./FeedbackForm";
|
|
@@ -37,43 +36,39 @@ export const FeedbackModal: React.FC<FeedbackModalProps> = ({
|
|
|
37
36
|
|
|
38
37
|
return (
|
|
39
38
|
<BaseModal visible={visible} onClose={onClose}>
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
<ScreenLayout
|
|
40
|
+
scrollable={true}
|
|
41
|
+
edges={[]}
|
|
42
|
+
keyboardAvoiding={true}
|
|
43
|
+
contentContainerStyle={styles.content}
|
|
44
|
+
hideScrollIndicator={false}
|
|
45
|
+
>
|
|
46
|
+
<View style={[styles.header, { borderBottomColor: tokens.colors.border }]}>
|
|
47
|
+
<View style={styles.headerText}>
|
|
48
|
+
<AtomicText type="headlineSmall" color="textPrimary">
|
|
49
|
+
{title}
|
|
50
|
+
</AtomicText>
|
|
51
|
+
{subtitle && (
|
|
52
|
+
<AtomicText type="bodySmall" color="textSecondary" style={{ marginTop: 4 }}>
|
|
53
|
+
{subtitle}
|
|
49
54
|
</AtomicText>
|
|
50
|
-
|
|
51
|
-
<AtomicText type="bodySmall" color="textSecondary" style={{ marginTop: 4 }}>
|
|
52
|
-
{subtitle}
|
|
53
|
-
</AtomicText>
|
|
54
|
-
)}
|
|
55
|
-
</View>
|
|
56
|
-
<TouchableOpacity
|
|
57
|
-
onPress={onClose}
|
|
58
|
-
style={[styles.closeButton, { backgroundColor: tokens.colors.surfaceVariant }]}
|
|
59
|
-
>
|
|
60
|
-
<AtomicIcon name="close" size="sm" color="onSurface" />
|
|
61
|
-
</TouchableOpacity>
|
|
55
|
+
)}
|
|
62
56
|
</View>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
keyboardShouldPersistTaps="handled"
|
|
57
|
+
<TouchableOpacity
|
|
58
|
+
onPress={onClose}
|
|
59
|
+
style={[styles.closeButton, { backgroundColor: tokens.colors.surfaceVariant }]}
|
|
67
60
|
>
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
61
|
+
<AtomicIcon name="close" size="sm" color="onSurface" />
|
|
62
|
+
</TouchableOpacity>
|
|
63
|
+
</View>
|
|
64
|
+
|
|
65
|
+
<FeedbackForm
|
|
66
|
+
onSubmit={onSubmit}
|
|
67
|
+
initialType={initialType}
|
|
68
|
+
isSubmitting={isSubmitting}
|
|
69
|
+
texts={texts}
|
|
70
|
+
/>
|
|
71
|
+
</ScreenLayout>
|
|
77
72
|
</BaseModal>
|
|
78
73
|
);
|
|
79
74
|
};
|
|
@@ -81,12 +76,6 @@ export const FeedbackModal: React.FC<FeedbackModalProps> = ({
|
|
|
81
76
|
|
|
82
77
|
const getStyles = (_tokens: ReturnType<typeof useAppDesignTokens>) =>
|
|
83
78
|
StyleSheet.create({
|
|
84
|
-
safeArea: {
|
|
85
|
-
flex: 1,
|
|
86
|
-
},
|
|
87
|
-
keyboardView: {
|
|
88
|
-
flex: 1,
|
|
89
|
-
},
|
|
90
79
|
header: {
|
|
91
80
|
flexDirection: "row",
|
|
92
81
|
justifyContent: "space-between",
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GamificationScreen - Pure Presentational Component
|
|
3
|
+
* Renders the gamification dashboard with all data provided as props
|
|
4
|
+
* Under 200 lines - only presentation logic
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { View, ScrollView } from "react-native";
|
|
9
|
+
import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
|
|
10
|
+
import { LevelProgress } from "../LevelProgress";
|
|
11
|
+
import { StreakDisplay } from "../StreakDisplay";
|
|
12
|
+
import { Header } from "./Header";
|
|
13
|
+
import { StatsGrid } from "./StatsGrid";
|
|
14
|
+
import { AchievementsList } from "./AchievementsList";
|
|
15
|
+
import { styles } from "./styles";
|
|
16
|
+
import type { GamificationScreenProps } from "./types";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Internal component that renders the screen with all props
|
|
20
|
+
*/
|
|
21
|
+
export const GamificationScreenInner: React.FC<GamificationScreenProps> = ({
|
|
22
|
+
title,
|
|
23
|
+
statsTitle,
|
|
24
|
+
achievementsTitle,
|
|
25
|
+
streakTitle,
|
|
26
|
+
levelProps,
|
|
27
|
+
stats,
|
|
28
|
+
achievements,
|
|
29
|
+
streakProps,
|
|
30
|
+
emptyAchievementsText,
|
|
31
|
+
containerStyle,
|
|
32
|
+
headerStyle,
|
|
33
|
+
titleStyle,
|
|
34
|
+
sectionTitleStyle,
|
|
35
|
+
accentColor,
|
|
36
|
+
backgroundColor,
|
|
37
|
+
cardBackgroundColor,
|
|
38
|
+
textColor,
|
|
39
|
+
subtextColor,
|
|
40
|
+
headerComponent,
|
|
41
|
+
}) => {
|
|
42
|
+
const tokens = useAppDesignTokens();
|
|
43
|
+
|
|
44
|
+
// Use tokens for fallbacks
|
|
45
|
+
const finalAccentColor = accentColor || tokens.colors.primary;
|
|
46
|
+
const finalBackgroundColor = backgroundColor || tokens.colors.backgroundPrimary;
|
|
47
|
+
const finalCardBackgroundColor = cardBackgroundColor || tokens.colors.surface;
|
|
48
|
+
const finalTextColor = textColor || tokens.colors.textPrimary;
|
|
49
|
+
const finalSubtextColor = subtextColor || tokens.colors.textSecondary;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<View style={[styles.container, { backgroundColor: finalBackgroundColor }, containerStyle]}>
|
|
53
|
+
{headerComponent}
|
|
54
|
+
|
|
55
|
+
<ScrollView
|
|
56
|
+
style={styles.scrollView}
|
|
57
|
+
contentContainerStyle={styles.scrollContent}
|
|
58
|
+
showsVerticalScrollIndicator={false}
|
|
59
|
+
>
|
|
60
|
+
{/* Header */}
|
|
61
|
+
<Header
|
|
62
|
+
title={title}
|
|
63
|
+
headerStyle={headerStyle}
|
|
64
|
+
titleStyle={titleStyle}
|
|
65
|
+
textColor={finalTextColor}
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
{/* Level Progress */}
|
|
69
|
+
<View style={styles.section}>
|
|
70
|
+
<LevelProgress
|
|
71
|
+
{...levelProps}
|
|
72
|
+
primaryColor={finalAccentColor}
|
|
73
|
+
backgroundColor={finalCardBackgroundColor}
|
|
74
|
+
textColor={finalTextColor}
|
|
75
|
+
subtextColor={finalSubtextColor}
|
|
76
|
+
/>
|
|
77
|
+
</View>
|
|
78
|
+
|
|
79
|
+
{/* Streak (if provided) */}
|
|
80
|
+
{streakProps && (
|
|
81
|
+
<View style={styles.section}>
|
|
82
|
+
<AtomicText
|
|
83
|
+
style={[styles.sectionTitle, { color: finalTextColor }, sectionTitleStyle]}
|
|
84
|
+
>
|
|
85
|
+
{streakTitle}
|
|
86
|
+
</AtomicText>
|
|
87
|
+
<StreakDisplay
|
|
88
|
+
{...streakProps}
|
|
89
|
+
primaryColor={finalAccentColor}
|
|
90
|
+
backgroundColor={finalCardBackgroundColor}
|
|
91
|
+
textColor={finalTextColor}
|
|
92
|
+
subtextColor={finalSubtextColor}
|
|
93
|
+
/>
|
|
94
|
+
</View>
|
|
95
|
+
)}
|
|
96
|
+
|
|
97
|
+
{/* Stats Grid */}
|
|
98
|
+
<StatsGrid
|
|
99
|
+
statsTitle={statsTitle}
|
|
100
|
+
stats={stats}
|
|
101
|
+
accentColor={finalAccentColor}
|
|
102
|
+
cardBackgroundColor={finalCardBackgroundColor}
|
|
103
|
+
textColor={finalTextColor}
|
|
104
|
+
subtextColor={finalSubtextColor}
|
|
105
|
+
sectionTitleStyle={sectionTitleStyle}
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
{/* Achievements */}
|
|
109
|
+
<AchievementsList
|
|
110
|
+
achievementsTitle={achievementsTitle}
|
|
111
|
+
achievements={achievements}
|
|
112
|
+
emptyAchievementsText={emptyAchievementsText}
|
|
113
|
+
accentColor={finalAccentColor}
|
|
114
|
+
cardBackgroundColor={finalCardBackgroundColor}
|
|
115
|
+
textColor={finalTextColor}
|
|
116
|
+
subtextColor={finalSubtextColor}
|
|
117
|
+
sectionTitleStyle={sectionTitleStyle}
|
|
118
|
+
/>
|
|
119
|
+
</ScrollView>
|
|
120
|
+
</View>
|
|
121
|
+
);
|
|
122
|
+
};
|
package/src/domains/gamification/components/GamificationScreen/GamificationScreenWithConfig.tsx
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GamificationScreen With Config
|
|
3
|
+
* Component that uses the hook to fetch data and render the screen
|
|
4
|
+
* Separated to satisfy React Hooks rules
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { GamificationScreenInner } from "./GamificationScreen";
|
|
9
|
+
import type { GamificationConfigProps } from "./types";
|
|
10
|
+
import type { GamificationScreenProps } from "./types";
|
|
11
|
+
import type { Achievement } from "../../types";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Component that uses the hook - separated to satisfy React Hooks rules
|
|
15
|
+
*/
|
|
16
|
+
export const GamificationScreenWithConfig: React.FC<GamificationConfigProps> = ({ config }) => {
|
|
17
|
+
// Import hook here to avoid conditional hook usage
|
|
18
|
+
const { useGamification } = require("../../hooks/useGamification");
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
points,
|
|
22
|
+
level,
|
|
23
|
+
streak,
|
|
24
|
+
achievements,
|
|
25
|
+
} = useGamification(config);
|
|
26
|
+
|
|
27
|
+
// Transform store achievements to UI props
|
|
28
|
+
const achievementItems = achievements.map((a: Achievement) => ({
|
|
29
|
+
...a,
|
|
30
|
+
title: a.title,
|
|
31
|
+
description: a.description,
|
|
32
|
+
icon: a.icon,
|
|
33
|
+
isUnlocked: a.isUnlocked,
|
|
34
|
+
progress: a.progress,
|
|
35
|
+
threshold: a.threshold,
|
|
36
|
+
id: a.id,
|
|
37
|
+
type: a.type
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
const screenProps: GamificationScreenProps = {
|
|
41
|
+
title: config.translations.title,
|
|
42
|
+
statsTitle: config.translations.statsTitle,
|
|
43
|
+
achievementsTitle: config.translations.achievementsTitle,
|
|
44
|
+
streakTitle: config.translations.streakTitle,
|
|
45
|
+
levelProps: {
|
|
46
|
+
level: level.currentLevel,
|
|
47
|
+
points: level.currentPoints,
|
|
48
|
+
pointsToNext: level.pointsToNext,
|
|
49
|
+
progress: level.progress,
|
|
50
|
+
levelTitle: config.translations.levelTitle,
|
|
51
|
+
showPoints: true,
|
|
52
|
+
},
|
|
53
|
+
streakProps: {
|
|
54
|
+
current: streak.current,
|
|
55
|
+
longest: streak.longest,
|
|
56
|
+
currentLabel: config.translations.currentStreak,
|
|
57
|
+
bestLabel: config.translations.bestStreak,
|
|
58
|
+
daysLabel: config.translations.days,
|
|
59
|
+
},
|
|
60
|
+
stats: [
|
|
61
|
+
{
|
|
62
|
+
label: config.translations.statsTitle,
|
|
63
|
+
value: points,
|
|
64
|
+
icon: "star",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
achievements: achievementItems,
|
|
68
|
+
emptyAchievementsText: config.translations.emptyAchievements,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return <GamificationScreenInner {...screenProps} />;
|
|
72
|
+
};
|
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
/**
|
|
3
2
|
* GamificationScreen Component
|
|
4
3
|
* Full gamification screen with integrated hook
|
|
5
4
|
* Generic for 100+ apps - NO hardcoded strings
|
|
5
|
+
*
|
|
6
|
+
* Split into multiple files to keep each under 200 lines:
|
|
7
|
+
* - GamificationScreen.tsx: Pure presentational component
|
|
8
|
+
* - GamificationScreenWithConfig.tsx: Config-based version with hook
|
|
9
|
+
* - index.tsx: Main entry point that routes to appropriate component
|
|
6
10
|
*/
|
|
7
11
|
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { StreakDisplay } from "../StreakDisplay";
|
|
12
|
-
import { Header } from "./Header";
|
|
13
|
-
import { StatsGrid } from "./StatsGrid";
|
|
14
|
-
import { AchievementsList } from "./AchievementsList";
|
|
15
|
-
import { styles } from "./styles";
|
|
12
|
+
import React from "react";
|
|
13
|
+
import { GamificationScreenInner } from "./GamificationScreen";
|
|
14
|
+
import { GamificationScreenWithConfig } from "./GamificationScreenWithConfig";
|
|
16
15
|
import type { GamificationScreenProps, GamificationConfigProps } from "./types";
|
|
17
|
-
import type { Achievement } from "../../types";
|
|
18
|
-
|
|
19
|
-
export type { GamificationScreenProps };
|
|
20
16
|
|
|
21
17
|
/**
|
|
22
18
|
* GamificationScreen that accepts either detailed props OR a config object
|
|
@@ -32,169 +28,3 @@ export const GamificationScreen: React.FC<GamificationScreenProps | Gamification
|
|
|
32
28
|
return <GamificationScreenInner {...(props as GamificationScreenProps)} />;
|
|
33
29
|
};
|
|
34
30
|
|
|
35
|
-
/**
|
|
36
|
-
* Component that uses the hook - separated to satisfy React Hooks rules
|
|
37
|
-
*/
|
|
38
|
-
const GamificationScreenWithConfig: React.FC<GamificationConfigProps> = ({ config }) => {
|
|
39
|
-
// Import hook here to avoid conditional hook usage
|
|
40
|
-
const { useGamification } = require("../../hooks/useGamification");
|
|
41
|
-
|
|
42
|
-
const {
|
|
43
|
-
points,
|
|
44
|
-
level,
|
|
45
|
-
streak,
|
|
46
|
-
achievements,
|
|
47
|
-
} = useGamification(config);
|
|
48
|
-
|
|
49
|
-
// Transform store achievements to UI props
|
|
50
|
-
const achievementItems = achievements.map((a: Achievement) => ({
|
|
51
|
-
...a,
|
|
52
|
-
title: a.title,
|
|
53
|
-
description: a.description,
|
|
54
|
-
icon: a.icon,
|
|
55
|
-
isUnlocked: a.isUnlocked,
|
|
56
|
-
progress: a.progress,
|
|
57
|
-
threshold: a.threshold,
|
|
58
|
-
id: a.id,
|
|
59
|
-
type: a.type
|
|
60
|
-
}));
|
|
61
|
-
|
|
62
|
-
const screenProps: GamificationScreenProps = {
|
|
63
|
-
title: config.translations.title,
|
|
64
|
-
statsTitle: config.translations.statsTitle,
|
|
65
|
-
achievementsTitle: config.translations.achievementsTitle,
|
|
66
|
-
streakTitle: config.translations.streakTitle,
|
|
67
|
-
levelProps: {
|
|
68
|
-
level: level.currentLevel,
|
|
69
|
-
points: level.currentPoints,
|
|
70
|
-
pointsToNext: level.pointsToNext,
|
|
71
|
-
progress: level.progress,
|
|
72
|
-
levelTitle: config.translations.levelTitle,
|
|
73
|
-
showPoints: true,
|
|
74
|
-
},
|
|
75
|
-
streakProps: {
|
|
76
|
-
current: streak.current,
|
|
77
|
-
longest: streak.longest,
|
|
78
|
-
currentLabel: config.translations.currentStreak,
|
|
79
|
-
bestLabel: config.translations.bestStreak,
|
|
80
|
-
daysLabel: config.translations.days,
|
|
81
|
-
},
|
|
82
|
-
stats: [
|
|
83
|
-
{
|
|
84
|
-
label: config.translations.statsTitle,
|
|
85
|
-
value: points,
|
|
86
|
-
icon: "star",
|
|
87
|
-
},
|
|
88
|
-
],
|
|
89
|
-
achievements: achievementItems,
|
|
90
|
-
emptyAchievementsText: config.translations.emptyAchievements,
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
return <GamificationScreenInner {...screenProps} />;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Internal component that renders the screen with all props
|
|
98
|
-
*/
|
|
99
|
-
const GamificationScreenInner: React.FC<GamificationScreenProps> = ({
|
|
100
|
-
title,
|
|
101
|
-
statsTitle,
|
|
102
|
-
achievementsTitle,
|
|
103
|
-
streakTitle,
|
|
104
|
-
levelProps,
|
|
105
|
-
stats,
|
|
106
|
-
achievements,
|
|
107
|
-
streakProps,
|
|
108
|
-
emptyAchievementsText,
|
|
109
|
-
containerStyle,
|
|
110
|
-
headerStyle,
|
|
111
|
-
titleStyle,
|
|
112
|
-
sectionTitleStyle,
|
|
113
|
-
accentColor,
|
|
114
|
-
backgroundColor,
|
|
115
|
-
cardBackgroundColor,
|
|
116
|
-
textColor,
|
|
117
|
-
subtextColor,
|
|
118
|
-
headerComponent,
|
|
119
|
-
}) => {
|
|
120
|
-
const tokens = useAppDesignTokens();
|
|
121
|
-
|
|
122
|
-
// Use tokens for fallbacks
|
|
123
|
-
const finalAccentColor = accentColor || tokens.colors.primary;
|
|
124
|
-
const finalBackgroundColor = backgroundColor || tokens.colors.backgroundPrimary;
|
|
125
|
-
const finalCardBackgroundColor = cardBackgroundColor || tokens.colors.surface;
|
|
126
|
-
const finalTextColor = textColor || tokens.colors.textPrimary;
|
|
127
|
-
const finalSubtextColor = subtextColor || tokens.colors.textSecondary;
|
|
128
|
-
|
|
129
|
-
return (
|
|
130
|
-
<View style={[styles.container, { backgroundColor: finalBackgroundColor }, containerStyle]}>
|
|
131
|
-
{headerComponent}
|
|
132
|
-
|
|
133
|
-
<ScrollView
|
|
134
|
-
style={styles.scrollView}
|
|
135
|
-
contentContainerStyle={styles.scrollContent}
|
|
136
|
-
showsVerticalScrollIndicator={false}
|
|
137
|
-
>
|
|
138
|
-
{/* Header */}
|
|
139
|
-
<Header
|
|
140
|
-
title={title}
|
|
141
|
-
headerStyle={headerStyle}
|
|
142
|
-
titleStyle={titleStyle}
|
|
143
|
-
textColor={finalTextColor}
|
|
144
|
-
/>
|
|
145
|
-
|
|
146
|
-
{/* Level Progress */}
|
|
147
|
-
<View style={styles.section}>
|
|
148
|
-
<LevelProgress
|
|
149
|
-
{...levelProps}
|
|
150
|
-
primaryColor={finalAccentColor}
|
|
151
|
-
backgroundColor={finalCardBackgroundColor}
|
|
152
|
-
textColor={finalTextColor}
|
|
153
|
-
subtextColor={finalSubtextColor}
|
|
154
|
-
/>
|
|
155
|
-
</View>
|
|
156
|
-
|
|
157
|
-
{/* Streak (if provided) */}
|
|
158
|
-
{streakProps && (
|
|
159
|
-
<View style={styles.section}>
|
|
160
|
-
<AtomicText
|
|
161
|
-
style={[styles.sectionTitle, { color: finalTextColor }, sectionTitleStyle]}
|
|
162
|
-
>
|
|
163
|
-
{streakTitle}
|
|
164
|
-
</AtomicText>
|
|
165
|
-
<StreakDisplay
|
|
166
|
-
{...streakProps}
|
|
167
|
-
primaryColor={finalAccentColor}
|
|
168
|
-
backgroundColor={finalCardBackgroundColor}
|
|
169
|
-
textColor={finalTextColor}
|
|
170
|
-
subtextColor={finalSubtextColor}
|
|
171
|
-
/>
|
|
172
|
-
</View>
|
|
173
|
-
)}
|
|
174
|
-
|
|
175
|
-
{/* Stats Grid */}
|
|
176
|
-
<StatsGrid
|
|
177
|
-
statsTitle={statsTitle}
|
|
178
|
-
stats={stats}
|
|
179
|
-
accentColor={finalAccentColor}
|
|
180
|
-
cardBackgroundColor={finalCardBackgroundColor}
|
|
181
|
-
textColor={finalTextColor}
|
|
182
|
-
subtextColor={finalSubtextColor}
|
|
183
|
-
sectionTitleStyle={sectionTitleStyle}
|
|
184
|
-
/>
|
|
185
|
-
|
|
186
|
-
{/* Achievements */}
|
|
187
|
-
<AchievementsList
|
|
188
|
-
achievementsTitle={achievementsTitle}
|
|
189
|
-
achievements={achievements}
|
|
190
|
-
emptyAchievementsText={emptyAchievementsText}
|
|
191
|
-
accentColor={finalAccentColor}
|
|
192
|
-
cardBackgroundColor={finalCardBackgroundColor}
|
|
193
|
-
textColor={finalTextColor}
|
|
194
|
-
subtextColor={finalSubtextColor}
|
|
195
|
-
sectionTitleStyle={sectionTitleStyle}
|
|
196
|
-
/>
|
|
197
|
-
</ScrollView>
|
|
198
|
-
</View>
|
|
199
|
-
);
|
|
200
|
-
};
|
|
@@ -10,4 +10,5 @@ export { AchievementToast, type AchievementToastProps } from "./AchievementToast
|
|
|
10
10
|
export { StreakDisplay, type StreakDisplayProps } from "./StreakDisplay";
|
|
11
11
|
export { StatsCard, type StatsCardProps } from "./StatsCard";
|
|
12
12
|
export { AchievementItem, type AchievementItemProps } from "./AchievementItem";
|
|
13
|
-
export { GamificationScreen
|
|
13
|
+
export { GamificationScreen } from "./GamificationScreen/index";
|
|
14
|
+
export type { GamificationScreenProps, GamificationConfigProps } from "./GamificationScreen/types";
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
* Shared logic for legal document screens
|
|
4
4
|
*/
|
|
5
5
|
import React from "react";
|
|
6
|
-
import { View,
|
|
7
|
-
import {
|
|
8
|
-
import { useAppDesignTokens, type DesignTokens } from "@umituz/react-native-design-system";
|
|
6
|
+
import { View, StyleSheet } from "react-native";
|
|
7
|
+
import { useAppDesignTokens, type DesignTokens, ScreenLayout } from "@umituz/react-native-design-system";
|
|
9
8
|
import { AtomicText, AtomicButton } from "@umituz/react-native-design-system";
|
|
10
9
|
import { UrlHandlerService } from "../../domain/services/UrlHandlerService";
|
|
11
10
|
import { ContentValidationService } from "../../domain/services/ContentValidationService";
|
|
@@ -35,7 +34,6 @@ export const LegalContentScreen: React.FC<LegalContentScreenProps> = React.memo(
|
|
|
35
34
|
createStyles,
|
|
36
35
|
}) => {
|
|
37
36
|
const tokens = useAppDesignTokens();
|
|
38
|
-
const insets = useSafeAreaInsets();
|
|
39
37
|
|
|
40
38
|
const styles = React.useMemo(() => {
|
|
41
39
|
const cacheKey = StyleCacheService.createTokenCacheKey(tokens);
|
|
@@ -58,14 +56,6 @@ export const LegalContentScreen: React.FC<LegalContentScreenProps> = React.memo(
|
|
|
58
56
|
}
|
|
59
57
|
}, [onUrlPress, url]);
|
|
60
58
|
|
|
61
|
-
const containerStyle = React.useMemo(() => [
|
|
62
|
-
styles.container,
|
|
63
|
-
{
|
|
64
|
-
backgroundColor: tokens.colors.backgroundPrimary,
|
|
65
|
-
paddingTop: insets.top,
|
|
66
|
-
},
|
|
67
|
-
], [styles.container, tokens.colors.backgroundPrimary, insets.top]);
|
|
68
|
-
|
|
69
59
|
const showContent = React.useMemo(() => !!(content), [content]);
|
|
70
60
|
const showUrlSection = React.useMemo(() =>
|
|
71
61
|
ContentValidationService.shouldShowUrlSection(url, onUrlPress),
|
|
@@ -107,23 +97,23 @@ export const LegalContentScreen: React.FC<LegalContentScreenProps> = React.memo(
|
|
|
107
97
|
}, [showContent, showUrlSection, styles, content, viewOnlineText, openText, handleUrlPress]);
|
|
108
98
|
|
|
109
99
|
return (
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
100
|
+
<ScreenLayout
|
|
101
|
+
testID={testID}
|
|
102
|
+
scrollable={true}
|
|
103
|
+
hideScrollIndicator={false}
|
|
104
|
+
contentContainerStyle={styles.scrollContent}
|
|
105
|
+
>
|
|
106
|
+
<View style={styles.content}>
|
|
107
|
+
<AtomicText
|
|
108
|
+
type="headlineLarge"
|
|
109
|
+
color="primary"
|
|
110
|
+
style={styles.title}
|
|
111
|
+
>
|
|
112
|
+
{title}
|
|
113
|
+
</AtomicText>
|
|
123
114
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
</View>
|
|
115
|
+
{contentSection}
|
|
116
|
+
</View>
|
|
117
|
+
</ScreenLayout>
|
|
128
118
|
);
|
|
129
119
|
});
|
|
@@ -22,7 +22,11 @@ export class NotificationService {
|
|
|
22
22
|
|
|
23
23
|
private constructor() {
|
|
24
24
|
// Configure notification handler on initialization
|
|
25
|
-
|
|
25
|
+
try {
|
|
26
|
+
NotificationManager.configure();
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error('[NotificationService] Failed to configure notification handler:', error);
|
|
29
|
+
}
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
static getInstance(): NotificationService {
|
package/src/index.ts
CHANGED
|
@@ -91,7 +91,6 @@ export type { SettingsSectionProps } from './presentation/components/SettingsSec
|
|
|
91
91
|
export { SettingsFooter } from './presentation/components/SettingsFooter';
|
|
92
92
|
export type { SettingsFooterProps } from './presentation/components/SettingsFooter';
|
|
93
93
|
|
|
94
|
-
export { SettingsErrorBoundary } from './presentation/components/SettingsErrorBoundary';
|
|
95
94
|
|
|
96
95
|
|
|
97
96
|
// =============================================================================
|