@umituz/react-native-settings 4.20.62 → 4.21.2

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 (70) hide show
  1. package/package.json +6 -61
  2. package/src/domains/feedback/domain/entities/FeedbackEntity.ts +8 -8
  3. package/src/domains/gamification/components/AchievementCard.tsx +142 -0
  4. package/src/domains/gamification/components/AchievementItem.tsx +182 -0
  5. package/src/domains/gamification/components/AchievementToast.tsx +122 -0
  6. package/src/domains/gamification/components/GamificationScreen/AchievementsList.tsx +84 -0
  7. package/src/domains/gamification/components/GamificationScreen/Header.tsx +29 -0
  8. package/src/domains/gamification/components/GamificationScreen/StatsGrid.tsx +51 -0
  9. package/src/domains/gamification/components/GamificationScreen/index.tsx +111 -0
  10. package/src/domains/gamification/components/GamificationScreen/styles.ts +43 -0
  11. package/src/domains/gamification/components/GamificationScreen/types.ts +77 -0
  12. package/src/domains/gamification/components/GamificationScreenWrapper.tsx +4 -4
  13. package/src/domains/gamification/components/GamificationSettingsItem.tsx +1 -1
  14. package/src/domains/gamification/components/LevelProgress.tsx +129 -0
  15. package/src/domains/gamification/components/PointsBadge.tsx +60 -0
  16. package/src/domains/gamification/components/StatsCard.tsx +89 -0
  17. package/src/domains/gamification/components/StreakDisplay.tsx +119 -0
  18. package/src/domains/gamification/components/index.ts +13 -0
  19. package/src/domains/gamification/examples/gamification.config.example.ts +1 -1
  20. package/src/domains/gamification/hooks/useGamification.ts +91 -0
  21. package/src/domains/gamification/index.ts +46 -19
  22. package/src/domains/gamification/store/gamificationStore.ts +162 -0
  23. package/src/domains/gamification/types/index.ts +95 -23
  24. package/src/domains/gamification/types/settings.ts +28 -0
  25. package/src/domains/gamification/utils/calculations.ts +85 -0
  26. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -51
  27. package/.github/ISSUE_TEMPLATE/documentation.md +0 -52
  28. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -63
  29. package/.github/PULL_REQUEST_TEMPLATE.md +0 -84
  30. package/AI_AGENT_GUIDELINES.md +0 -367
  31. package/ARCHITECTURE.md +0 -246
  32. package/CHANGELOG.md +0 -67
  33. package/CODE_OF_CONDUCT.md +0 -75
  34. package/CONTRIBUTING.md +0 -107
  35. package/DOCUMENTATION_MIGRATION.md +0 -319
  36. package/DOCUMENTATION_TEMPLATE.md +0 -155
  37. package/SECURITY.md +0 -98
  38. package/SETTINGS_SCREEN_GUIDE.md +0 -185
  39. package/TESTING.md +0 -358
  40. package/src/__tests__/integration.test.tsx +0 -371
  41. package/src/__tests__/performance.test.tsx +0 -369
  42. package/src/__tests__/setup.test.tsx +0 -20
  43. package/src/__tests__/setup.ts +0 -154
  44. package/src/domains/about/__tests__/integration.test.tsx +0 -328
  45. package/src/domains/about/__tests__/types.d.ts +0 -5
  46. package/src/domains/about/domain/entities/__tests__/AppInfo.test.ts +0 -93
  47. package/src/domains/about/infrastructure/repositories/__tests__/AboutRepository.test.ts +0 -153
  48. package/src/domains/about/presentation/components/__tests__/AboutContent.simple.test.tsx +0 -178
  49. package/src/domains/about/presentation/components/__tests__/AboutContent.test.tsx +0 -293
  50. package/src/domains/about/presentation/components/__tests__/AboutHeader.test.tsx +0 -201
  51. package/src/domains/about/presentation/components/__tests__/AboutSettingItem.test.tsx +0 -71
  52. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.simple.test.tsx +0 -229
  53. package/src/domains/about/presentation/hooks/__tests__/useAboutInfo.test.tsx +0 -240
  54. package/src/domains/about/presentation/screens/__tests__/AboutScreen.simple.test.tsx +0 -199
  55. package/src/domains/about/presentation/screens/__tests__/AboutScreen.test.tsx +0 -366
  56. package/src/domains/about/utils/__tests__/index.test.ts +0 -408
  57. package/src/domains/appearance/__tests__/components/AppearanceScreen.test.tsx +0 -195
  58. package/src/domains/appearance/__tests__/hooks/index.test.tsx +0 -232
  59. package/src/domains/appearance/__tests__/integration/index.test.tsx +0 -207
  60. package/src/domains/appearance/__tests__/services/appearanceService.test.ts +0 -299
  61. package/src/domains/appearance/__tests__/setup.ts +0 -88
  62. package/src/domains/appearance/__tests__/stores/appearanceStore.test.tsx +0 -175
  63. package/src/domains/cloud-sync/presentation/components/__tests__/CloudSyncSetting.test.tsx +0 -78
  64. package/src/domains/legal/__tests__/ContentValidationService.test.ts +0 -195
  65. package/src/domains/legal/__tests__/StyleCacheService.test.ts +0 -110
  66. package/src/domains/legal/__tests__/UrlHandlerService.test.ts +0 -71
  67. package/src/domains/legal/__tests__/setup.ts +0 -82
  68. package/src/presentation/components/__tests__/SettingsErrorBoundary.test.tsx +0 -186
  69. package/src/presentation/screens/__tests__/SettingsScreen.test.tsx +0 -322
  70. package/src/presentation/screens/hooks/__tests__/useFeatureDetection.test.tsx +0 -261
@@ -0,0 +1,51 @@
1
+ /**
2
+ * GamificationScreen StatsGrid Component
3
+ */
4
+
5
+ import React from "react";
6
+ import { View, Text, type TextStyle } from "react-native";
7
+ import { StatsCard } from "../StatsCard";
8
+ import { styles } from "./styles";
9
+ import type { StatsCardProps } from "../StatsCard";
10
+
11
+ export interface StatsGridProps {
12
+ statsTitle: string;
13
+ stats: Array<Omit<StatsCardProps, "accentColor" | "backgroundColor" | "textColor" | "subtextColor">>;
14
+ accentColor: string;
15
+ cardBackgroundColor: string;
16
+ textColor: string;
17
+ subtextColor: string;
18
+ sectionTitleStyle?: TextStyle;
19
+ }
20
+
21
+ export const StatsGrid: React.FC<StatsGridProps> = ({
22
+ statsTitle,
23
+ stats,
24
+ accentColor,
25
+ cardBackgroundColor,
26
+ textColor,
27
+ subtextColor,
28
+ sectionTitleStyle,
29
+ }) => {
30
+ if (stats.length === 0) return null;
31
+
32
+ return (
33
+ <View style={styles.section}>
34
+ <Text style={[styles.sectionTitle, { color: textColor }, sectionTitleStyle]}>
35
+ {statsTitle}
36
+ </Text>
37
+ <View style={styles.statsGrid}>
38
+ {stats.map((stat, index) => (
39
+ <StatsCard
40
+ key={index}
41
+ {...stat}
42
+ accentColor={accentColor}
43
+ backgroundColor={cardBackgroundColor}
44
+ textColor={textColor}
45
+ subtextColor={subtextColor}
46
+ />
47
+ ))}
48
+ </View>
49
+ </View>
50
+ );
51
+ };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * GamificationScreen Component
3
+ * Full gamification screen - all text via props
4
+ * Generic for 100+ apps - NO hardcoded strings
5
+ */
6
+
7
+ import React from "react";
8
+ import { View, ScrollView, Text, StyleSheet } from "react-native";
9
+ import { LevelProgress } from "../LevelProgress";
10
+ import { StreakDisplay } from "../StreakDisplay";
11
+ import { Header } from "./Header";
12
+ import { StatsGrid } from "./StatsGrid";
13
+ import { AchievementsList } from "./AchievementsList";
14
+ import { styles } from "./styles";
15
+ import type { GamificationScreenProps } from "./types";
16
+
17
+ export type { GamificationScreenProps };
18
+
19
+ export const GamificationScreen: React.FC<GamificationScreenProps> = ({
20
+ title,
21
+ statsTitle,
22
+ achievementsTitle,
23
+ streakTitle,
24
+ levelProps,
25
+ stats,
26
+ achievements,
27
+ streakProps,
28
+ emptyAchievementsText,
29
+ containerStyle,
30
+ headerStyle,
31
+ titleStyle,
32
+ sectionTitleStyle,
33
+ accentColor = "#FFD700",
34
+ backgroundColor = "#0A0A0A",
35
+ cardBackgroundColor = "#1A1A1A",
36
+ textColor = "#FFFFFF",
37
+ subtextColor = "#888888",
38
+ headerComponent,
39
+ }) => {
40
+ return (
41
+ <View style={[styles.container, { backgroundColor }, containerStyle]}>
42
+ {headerComponent}
43
+
44
+ <ScrollView
45
+ style={styles.scrollView}
46
+ contentContainerStyle={styles.scrollContent}
47
+ showsVerticalScrollIndicator={false}
48
+ >
49
+ {/* Header */}
50
+ <Header
51
+ title={title}
52
+ headerStyle={headerStyle}
53
+ titleStyle={titleStyle}
54
+ textColor={textColor}
55
+ />
56
+
57
+ {/* Level Progress */}
58
+ <View style={styles.section}>
59
+ <LevelProgress
60
+ {...levelProps}
61
+ primaryColor={accentColor}
62
+ backgroundColor={cardBackgroundColor}
63
+ textColor={textColor}
64
+ subtextColor={subtextColor}
65
+ />
66
+ </View>
67
+
68
+ {/* Streak (if provided) */}
69
+ {streakProps && (
70
+ <View style={styles.section}>
71
+ <Text
72
+ style={[styles.sectionTitle, { color: textColor }, sectionTitleStyle]}
73
+ >
74
+ {streakTitle}
75
+ </Text>
76
+ <StreakDisplay
77
+ {...streakProps}
78
+ primaryColor={accentColor}
79
+ backgroundColor={cardBackgroundColor}
80
+ textColor={textColor}
81
+ subtextColor={subtextColor}
82
+ />
83
+ </View>
84
+ )}
85
+
86
+ {/* Stats Grid */}
87
+ <StatsGrid
88
+ statsTitle={statsTitle}
89
+ stats={stats}
90
+ accentColor={accentColor}
91
+ cardBackgroundColor={cardBackgroundColor}
92
+ textColor={textColor}
93
+ subtextColor={subtextColor}
94
+ sectionTitleStyle={sectionTitleStyle}
95
+ />
96
+
97
+ {/* Achievements */}
98
+ <AchievementsList
99
+ achievementsTitle={achievementsTitle}
100
+ achievements={achievements}
101
+ emptyAchievementsText={emptyAchievementsText}
102
+ accentColor={accentColor}
103
+ cardBackgroundColor={cardBackgroundColor}
104
+ textColor={textColor}
105
+ subtextColor={subtextColor}
106
+ sectionTitleStyle={sectionTitleStyle}
107
+ />
108
+ </ScrollView>
109
+ </View>
110
+ );
111
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * GamificationScreen Styles
3
+ */
4
+
5
+ import { StyleSheet } from "react-native";
6
+
7
+ export const styles = StyleSheet.create({
8
+ container: {
9
+ flex: 1,
10
+ },
11
+ scrollView: {
12
+ flex: 1,
13
+ },
14
+ scrollContent: {
15
+ padding: 16,
16
+ paddingBottom: 32,
17
+ },
18
+ header: {
19
+ marginBottom: 20,
20
+ },
21
+ title: {
22
+ fontSize: 28,
23
+ fontWeight: "bold",
24
+ },
25
+ section: {
26
+ marginBottom: 24,
27
+ },
28
+ sectionTitle: {
29
+ fontSize: 18,
30
+ fontWeight: "600",
31
+ marginBottom: 12,
32
+ },
33
+ statsGrid: {
34
+ flexDirection: "row",
35
+ flexWrap: "wrap",
36
+ gap: 12,
37
+ },
38
+ emptyText: {
39
+ fontSize: 14,
40
+ textAlign: "center",
41
+ paddingVertical: 20,
42
+ },
43
+ });
@@ -0,0 +1,77 @@
1
+ /**
2
+ * GamificationScreen Types
3
+ * Generic types for 100+ apps - NO app-specific code
4
+ */
5
+
6
+ import type { LevelProgressProps } from "../LevelProgress";
7
+ import type { StatsCardProps } from "../StatsCard";
8
+ import type { AchievementItemProps } from "../AchievementItem";
9
+ import type { StreakDisplayProps } from "../StreakDisplay";
10
+ import type { ViewStyle, TextStyle } from "react-native";
11
+
12
+ export interface GamificationScreenProps {
13
+ // Section titles (all via props)
14
+ title: string;
15
+ statsTitle: string;
16
+ achievementsTitle: string;
17
+ streakTitle: string;
18
+
19
+ // Level data
20
+ levelProps: Omit<
21
+ LevelProgressProps,
22
+ "primaryColor" | "backgroundColor" | "textColor" | "subtextColor"
23
+ >;
24
+
25
+ // Stats data
26
+ stats: Array<
27
+ Omit<
28
+ StatsCardProps,
29
+ "accentColor" | "backgroundColor" | "textColor" | "subtextColor"
30
+ >
31
+ >;
32
+
33
+ // Achievements data
34
+ achievements: Array<
35
+ Omit<
36
+ AchievementItemProps,
37
+ | "accentColor"
38
+ | "backgroundColor"
39
+ | "textColor"
40
+ | "subtextColor"
41
+ | "lockedOpacity"
42
+ >
43
+ >;
44
+
45
+ // Streak data (optional)
46
+ streakProps?: Omit<
47
+ StreakDisplayProps,
48
+ "primaryColor" | "backgroundColor" | "textColor" | "subtextColor"
49
+ >;
50
+
51
+ // Empty state
52
+ emptyAchievementsText?: string;
53
+
54
+ // Customization
55
+ containerStyle?: ViewStyle;
56
+ headerStyle?: ViewStyle;
57
+ titleStyle?: TextStyle;
58
+ sectionTitleStyle?: TextStyle;
59
+
60
+ // Colors (applied to all child components)
61
+ accentColor?: string;
62
+ backgroundColor?: string;
63
+ cardBackgroundColor?: string;
64
+ textColor?: string;
65
+ subtextColor?: string;
66
+
67
+ // Header component (optional - for back button etc)
68
+ headerComponent?: React.ReactNode;
69
+ }
70
+
71
+ export interface GamificationScreenStyleProps {
72
+ accentColor: string;
73
+ backgroundColor: string;
74
+ cardBackgroundColor: string;
75
+ textColor: string;
76
+ subtextColor: string;
77
+ }
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Gamification Screen Component
3
- * Wrapper for @umituz/react-native-gamification screen
3
+ * Wrapper for gamification screen
4
4
  */
5
5
 
6
6
  import React, { useMemo } from "react";
7
- import { GamificationScreen as BaseGamificationScreen } from "@umituz/react-native-gamification";
8
- import { useGamification } from "@umituz/react-native-gamification";
7
+ import { GamificationScreen as BaseGamificationScreen } from "./GamificationScreen";
8
+ import { useGamification } from "../hooks/useGamification";
9
9
  import { useLocalization } from "@umituz/react-native-localization";
10
- import type { GamificationSettingsConfig } from "../types";
10
+ import type { GamificationSettingsConfig } from "../types/settings";
11
11
 
12
12
  export interface GamificationScreenWrapperProps {
13
13
  config: GamificationSettingsConfig;
@@ -5,7 +5,7 @@
5
5
 
6
6
  import React from "react";
7
7
  import { SettingsItemCard } from "../../../presentation/components/SettingsItemCard";
8
- import type { GamificationMenuConfig } from "../types";
8
+ import type { GamificationMenuConfig } from "../types/settings";
9
9
 
10
10
  export interface GamificationSettingsItemProps {
11
11
  config: GamificationMenuConfig;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * LevelProgress Component
3
+ * Displays level and progress - all text via props
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, Text, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
8
+
9
+ export interface LevelProgressProps {
10
+ level: number;
11
+ points: number;
12
+ levelTitle: string;
13
+ pointsToNext: number;
14
+ progress: number;
15
+ showPoints?: boolean;
16
+ // Customization
17
+ containerStyle?: ViewStyle;
18
+ titleStyle?: TextStyle;
19
+ subtitleStyle?: TextStyle;
20
+ progressBarStyle?: ViewStyle;
21
+ progressFillStyle?: ViewStyle;
22
+ badgeStyle?: ViewStyle;
23
+ badgeTextStyle?: TextStyle;
24
+ // Colors (design system integration)
25
+ primaryColor?: string;
26
+ secondaryColor?: string;
27
+ backgroundColor?: string;
28
+ textColor?: string;
29
+ subtextColor?: string;
30
+ }
31
+
32
+ export const LevelProgress: React.FC<LevelProgressProps> = ({
33
+ level,
34
+ points,
35
+ levelTitle,
36
+ pointsToNext,
37
+ progress,
38
+ showPoints = true,
39
+ containerStyle,
40
+ titleStyle,
41
+ subtitleStyle,
42
+ progressBarStyle,
43
+ progressFillStyle,
44
+ badgeStyle,
45
+ badgeTextStyle,
46
+ primaryColor = "#FFD700",
47
+ secondaryColor = "#2A2A2A",
48
+ backgroundColor = "#1A1A1A",
49
+ textColor = "#FFFFFF",
50
+ subtextColor = "#888888",
51
+ }) => {
52
+ return (
53
+ <View style={[styles.container, { backgroundColor }, containerStyle]}>
54
+ <View style={styles.header}>
55
+ <View style={styles.titleSection}>
56
+ <Text style={[styles.levelTitle, { color: textColor }, titleStyle]}>
57
+ {levelTitle}
58
+ </Text>
59
+ {showPoints && (
60
+ <Text style={[styles.subtitle, { color: subtextColor }, subtitleStyle]}>
61
+ {points} / {points + pointsToNext}
62
+ </Text>
63
+ )}
64
+ </View>
65
+
66
+ <View style={[styles.badge, { backgroundColor: `${primaryColor}20`, borderColor: `${primaryColor}40` }, badgeStyle]}>
67
+ <Text style={[styles.badgeText, { color: primaryColor }, badgeTextStyle]}>
68
+ {level}
69
+ </Text>
70
+ </View>
71
+ </View>
72
+
73
+ <View style={[styles.progressBar, { backgroundColor: secondaryColor }, progressBarStyle]}>
74
+ <View
75
+ style={[
76
+ styles.progressFill,
77
+ { width: `${Math.min(100, progress)}%`, backgroundColor: primaryColor },
78
+ progressFillStyle,
79
+ ]}
80
+ />
81
+ </View>
82
+ </View>
83
+ );
84
+ };
85
+
86
+ const styles = StyleSheet.create({
87
+ container: {
88
+ borderRadius: 16,
89
+ padding: 16,
90
+ },
91
+ header: {
92
+ flexDirection: "row",
93
+ justifyContent: "space-between",
94
+ alignItems: "center",
95
+ marginBottom: 12,
96
+ },
97
+ titleSection: {
98
+ flex: 1,
99
+ },
100
+ levelTitle: {
101
+ fontSize: 18,
102
+ fontWeight: "700",
103
+ },
104
+ subtitle: {
105
+ fontSize: 14,
106
+ marginTop: 2,
107
+ },
108
+ badge: {
109
+ width: 48,
110
+ height: 48,
111
+ borderRadius: 24,
112
+ justifyContent: "center",
113
+ alignItems: "center",
114
+ borderWidth: 2,
115
+ },
116
+ badgeText: {
117
+ fontSize: 18,
118
+ fontWeight: "bold",
119
+ },
120
+ progressBar: {
121
+ height: 8,
122
+ borderRadius: 4,
123
+ overflow: "hidden",
124
+ },
125
+ progressFill: {
126
+ height: "100%",
127
+ borderRadius: 4,
128
+ },
129
+ });
@@ -0,0 +1,60 @@
1
+ /**
2
+ * PointsBadge Component
3
+ * Displays points with optional icon - all text via props
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, Text, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
8
+
9
+ export interface PointsBadgeProps {
10
+ points: number;
11
+ icon?: React.ReactNode;
12
+ // Customization
13
+ containerStyle?: ViewStyle;
14
+ textStyle?: TextStyle;
15
+ // Colors
16
+ backgroundColor?: string;
17
+ textColor?: string;
18
+ borderColor?: string;
19
+ }
20
+
21
+ export const PointsBadge: React.FC<PointsBadgeProps> = ({
22
+ points,
23
+ icon,
24
+ containerStyle,
25
+ textStyle,
26
+ backgroundColor = "#FFD70020",
27
+ textColor = "#FFD700",
28
+ borderColor = "#FFD70040",
29
+ }) => {
30
+ return (
31
+ <View
32
+ style={[
33
+ styles.container,
34
+ { backgroundColor, borderColor },
35
+ containerStyle,
36
+ ]}
37
+ >
38
+ {icon}
39
+ <Text style={[styles.text, { color: textColor }, textStyle]}>
40
+ {points}
41
+ </Text>
42
+ </View>
43
+ );
44
+ };
45
+
46
+ const styles = StyleSheet.create({
47
+ container: {
48
+ flexDirection: "row",
49
+ alignItems: "center",
50
+ gap: 6,
51
+ paddingHorizontal: 12,
52
+ paddingVertical: 6,
53
+ borderRadius: 20,
54
+ borderWidth: 1,
55
+ },
56
+ text: {
57
+ fontSize: 16,
58
+ fontWeight: "bold",
59
+ },
60
+ });
@@ -0,0 +1,89 @@
1
+ /**
2
+ * StatsCard Component
3
+ * Displays a stat with icon - all text via props
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, Text, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
8
+
9
+ export interface StatsCardProps {
10
+ value: number;
11
+ label: string;
12
+ icon: React.ReactNode;
13
+ suffix?: string;
14
+ // Customization
15
+ containerStyle?: ViewStyle;
16
+ valueStyle?: TextStyle;
17
+ labelStyle?: TextStyle;
18
+ // Colors
19
+ accentColor?: string;
20
+ backgroundColor?: string;
21
+ textColor?: string;
22
+ subtextColor?: string;
23
+ }
24
+
25
+ export const StatsCard: React.FC<StatsCardProps> = ({
26
+ value,
27
+ label,
28
+ icon,
29
+ suffix,
30
+ containerStyle,
31
+ valueStyle,
32
+ labelStyle,
33
+ accentColor = "#FFD700",
34
+ backgroundColor = "#1A1A1A",
35
+ textColor = "#FFFFFF",
36
+ subtextColor = "#888888",
37
+ }) => {
38
+ return (
39
+ <View style={[styles.container, { backgroundColor }, containerStyle]}>
40
+ <View style={[styles.iconContainer, { backgroundColor: `${accentColor}15` }]}>
41
+ {icon}
42
+ </View>
43
+ <View style={styles.valueRow}>
44
+ <Text style={[styles.value, { color: textColor }, valueStyle]}>
45
+ {value}
46
+ </Text>
47
+ {suffix && (
48
+ <Text style={[styles.suffix, { color: subtextColor }]}>{suffix}</Text>
49
+ )}
50
+ </View>
51
+ <Text style={[styles.label, { color: subtextColor }, labelStyle]}>
52
+ {label}
53
+ </Text>
54
+ </View>
55
+ );
56
+ };
57
+
58
+ const styles = StyleSheet.create({
59
+ container: {
60
+ flex: 1,
61
+ minWidth: "45%",
62
+ borderRadius: 12,
63
+ padding: 12,
64
+ },
65
+ iconContainer: {
66
+ width: 36,
67
+ height: 36,
68
+ borderRadius: 18,
69
+ alignItems: "center",
70
+ justifyContent: "center",
71
+ marginBottom: 8,
72
+ },
73
+ valueRow: {
74
+ flexDirection: "row",
75
+ alignItems: "baseline",
76
+ gap: 4,
77
+ },
78
+ value: {
79
+ fontSize: 24,
80
+ fontWeight: "bold",
81
+ },
82
+ suffix: {
83
+ fontSize: 12,
84
+ },
85
+ label: {
86
+ fontSize: 12,
87
+ marginTop: 2,
88
+ },
89
+ });
@@ -0,0 +1,119 @@
1
+ /**
2
+ * StreakDisplay Component
3
+ * Displays streak information - all text via props
4
+ */
5
+
6
+ import React from "react";
7
+ import { View, Text, StyleSheet, type ViewStyle, type TextStyle } from "react-native";
8
+
9
+ export interface StreakDisplayProps {
10
+ current: number;
11
+ longest: number;
12
+ currentLabel: string; // e.g., "Current Streak"
13
+ bestLabel: string; // e.g., "Best"
14
+ daysLabel: string; // e.g., "days"
15
+ icon?: React.ReactNode;
16
+ // Customization
17
+ containerStyle?: ViewStyle;
18
+ numberStyle?: TextStyle;
19
+ labelStyle?: TextStyle;
20
+ // Colors
21
+ primaryColor?: string;
22
+ backgroundColor?: string;
23
+ textColor?: string;
24
+ subtextColor?: string;
25
+ }
26
+
27
+ export const StreakDisplay: React.FC<StreakDisplayProps> = ({
28
+ current,
29
+ longest,
30
+ currentLabel,
31
+ bestLabel,
32
+ daysLabel,
33
+ icon,
34
+ containerStyle,
35
+ numberStyle,
36
+ labelStyle,
37
+ primaryColor = "#FF6B35",
38
+ backgroundColor = "#1A1A1A",
39
+ textColor = "#FFFFFF",
40
+ subtextColor = "#888888",
41
+ }) => {
42
+ return (
43
+ <View style={[styles.container, { backgroundColor }, containerStyle]}>
44
+ <View style={styles.mainStreak}>
45
+ {icon && <View style={styles.iconContainer}>{icon}</View>}
46
+ <View style={styles.streakInfo}>
47
+ <Text style={[styles.number, { color: primaryColor }, numberStyle]}>
48
+ {current}
49
+ </Text>
50
+ <Text style={[styles.label, { color: subtextColor }, labelStyle]}>
51
+ {daysLabel}
52
+ </Text>
53
+ </View>
54
+ <Text style={[styles.currentLabel, { color: textColor }]}>
55
+ {currentLabel}
56
+ </Text>
57
+ </View>
58
+
59
+ <View style={[styles.bestStreak, { backgroundColor: `${primaryColor}20` }]}>
60
+ <Text style={[styles.bestLabel, { color: subtextColor }]}>
61
+ {bestLabel}
62
+ </Text>
63
+ <Text style={[styles.bestNumber, { color: primaryColor }]}>
64
+ {longest}
65
+ </Text>
66
+ </View>
67
+ </View>
68
+ );
69
+ };
70
+
71
+ const styles = StyleSheet.create({
72
+ container: {
73
+ borderRadius: 16,
74
+ padding: 16,
75
+ flexDirection: "row",
76
+ alignItems: "center",
77
+ justifyContent: "space-between",
78
+ },
79
+ mainStreak: {
80
+ flexDirection: "row",
81
+ alignItems: "center",
82
+ gap: 12,
83
+ },
84
+ iconContainer: {
85
+ width: 40,
86
+ height: 40,
87
+ justifyContent: "center",
88
+ alignItems: "center",
89
+ },
90
+ streakInfo: {
91
+ alignItems: "center",
92
+ },
93
+ number: {
94
+ fontSize: 32,
95
+ fontWeight: "bold",
96
+ },
97
+ label: {
98
+ fontSize: 12,
99
+ textTransform: "uppercase",
100
+ },
101
+ currentLabel: {
102
+ fontSize: 14,
103
+ fontWeight: "500",
104
+ },
105
+ bestStreak: {
106
+ paddingHorizontal: 12,
107
+ paddingVertical: 8,
108
+ borderRadius: 12,
109
+ alignItems: "center",
110
+ },
111
+ bestLabel: {
112
+ fontSize: 11,
113
+ textTransform: "uppercase",
114
+ },
115
+ bestNumber: {
116
+ fontSize: 18,
117
+ fontWeight: "bold",
118
+ },
119
+ });