@umituz/react-native-settings 4.23.81 → 4.23.83
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 +49 -3
- package/src/domains/about/presentation/screens/AboutScreenContent.tsx +2 -4
- package/src/domains/disclaimer/presentation/screens/DisclaimerScreen.tsx +15 -1
- package/src/domains/faqs/presentation/screens/FAQScreen.tsx +25 -23
- package/src/domains/feedback/presentation/components/FeedbackForm.styles.ts +51 -0
- package/src/domains/feedback/presentation/components/FeedbackForm.tsx +3 -49
- package/src/domains/gamification/components/GamificationScreen/GamificationScreen.tsx +54 -57
- package/src/domains/legal/presentation/screens/LegalContentScreen.tsx +8 -8
- package/src/domains/legal/presentation/screens/LegalScreen.tsx +14 -3
- package/src/domains/localization/index.ts +2 -2
- package/src/domains/localization/presentation/providers/{LocalizationProvider.tsx → LocalizationManager.tsx} +1 -1
- package/src/domains/localization/presentation/screens/LanguageSelectionScreen.tsx +1 -1
- package/src/domains/notifications/index.ts +1 -1
- package/src/domains/notifications/presentation/screens/NotificationsScreen.tsx +53 -26
- package/src/domains/notifications/reminders/presentation/components/ReminderForm.constants.ts +35 -0
- package/src/domains/notifications/reminders/presentation/components/ReminderForm.styles.ts +22 -0
- package/src/domains/notifications/reminders/presentation/components/ReminderForm.tsx +13 -57
- package/src/domains/notifications/reminders/presentation/screens/ReminderListScreen.tsx +25 -10
- package/src/domains/video-tutorials/presentation/screens/VideoTutorialsScreen.tsx +17 -6
- package/src/presentation/components/SettingsFooter.tsx +3 -3
- package/src/presentation/navigation/SettingsStackNavigator.tsx +32 -174
- package/src/presentation/navigation/hooks/index.ts +1 -0
- package/src/presentation/navigation/hooks/useSettingsScreens.ts +163 -0
- package/src/presentation/screens/SettingsScreen.tsx +38 -58
- package/src/presentation/screens/components/SettingsHeader.tsx +29 -43
- package/src/presentation/screens/hooks/useSettingsScreen.ts +64 -0
- package/src/utils/appUtils.ts +43 -0
- package/src/utils/index.ts +1 -0
- package/src/domains/about/presentation/screens/AboutScreenContainer.tsx +0 -109
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import type { StackScreen } from "@umituz/react-native-design-system";
|
|
3
|
+
import { LanguageSelectionScreen } from "../../../domains/localization";
|
|
4
|
+
import { NotificationSettingsScreen } from "../../../domains/notifications";
|
|
5
|
+
import { AccountScreen } from "@umituz/react-native-auth";
|
|
6
|
+
import { SettingsScreen } from "../../screens/SettingsScreen";
|
|
7
|
+
import { AppearanceScreen } from "../../screens/AppearanceScreen";
|
|
8
|
+
import { FAQScreen } from "../../../domains/faqs";
|
|
9
|
+
import { AboutScreen } from "../../../domains/about";
|
|
10
|
+
import { LegalScreen } from "../../../domains/legal";
|
|
11
|
+
import { GamificationScreen } from "../../../domains/gamification";
|
|
12
|
+
import type { SettingsStackNavigatorProps, AdditionalScreen } from "../types";
|
|
13
|
+
|
|
14
|
+
export interface UseSettingsScreensProps extends SettingsStackNavigatorProps {
|
|
15
|
+
aboutConfig: any;
|
|
16
|
+
legalProps: any;
|
|
17
|
+
notificationTranslations: any;
|
|
18
|
+
quietHoursTranslations: any;
|
|
19
|
+
t: (key: string) => string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const useSettingsScreens = (props: UseSettingsScreensProps): StackScreen[] => {
|
|
23
|
+
const {
|
|
24
|
+
appInfo,
|
|
25
|
+
config,
|
|
26
|
+
showUserProfile,
|
|
27
|
+
userProfile,
|
|
28
|
+
devSettings,
|
|
29
|
+
customSections,
|
|
30
|
+
showHeader,
|
|
31
|
+
showCloseButton,
|
|
32
|
+
onClose,
|
|
33
|
+
aboutConfig,
|
|
34
|
+
legalProps,
|
|
35
|
+
notificationTranslations,
|
|
36
|
+
quietHoursTranslations,
|
|
37
|
+
faqData,
|
|
38
|
+
additionalScreens,
|
|
39
|
+
gamificationConfig,
|
|
40
|
+
accountConfig,
|
|
41
|
+
t,
|
|
42
|
+
} = props;
|
|
43
|
+
|
|
44
|
+
return useMemo(() => {
|
|
45
|
+
const baseScreens: StackScreen[] = [
|
|
46
|
+
{
|
|
47
|
+
name: "SettingsMain",
|
|
48
|
+
options: { headerShown: false },
|
|
49
|
+
children: () => React.createElement(SettingsScreen, {
|
|
50
|
+
config,
|
|
51
|
+
appVersion: appInfo.version,
|
|
52
|
+
showUserProfile,
|
|
53
|
+
userProfile,
|
|
54
|
+
devSettings,
|
|
55
|
+
customSections,
|
|
56
|
+
showHeader,
|
|
57
|
+
showCloseButton,
|
|
58
|
+
onClose,
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "Appearance",
|
|
63
|
+
component: AppearanceScreen as any,
|
|
64
|
+
options: { headerShown: false },
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "About",
|
|
68
|
+
options: { headerShown: false },
|
|
69
|
+
children: () => React.createElement(AboutScreen, { config: aboutConfig }),
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "Legal",
|
|
73
|
+
options: { headerShown: false },
|
|
74
|
+
children: () => React.createElement(LegalScreen, legalProps),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "Notifications",
|
|
78
|
+
options: { headerShown: false },
|
|
79
|
+
children: () => React.createElement(NotificationSettingsScreen, {
|
|
80
|
+
translations: notificationTranslations,
|
|
81
|
+
quietHoursTranslations,
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
const faqScreen: StackScreen | null = (faqData && faqData.categories?.length > 0)
|
|
87
|
+
? {
|
|
88
|
+
name: "FAQ",
|
|
89
|
+
options: { headerShown: false },
|
|
90
|
+
children: () => React.createElement(FAQScreen, {
|
|
91
|
+
categories: faqData.categories,
|
|
92
|
+
searchPlaceholder: t("settings.faqs.searchPlaceholder"),
|
|
93
|
+
emptySearchTitle: t("settings.faqs.emptySearchTitle"),
|
|
94
|
+
emptySearchMessage: t("settings.faqs.emptySearchMessage"),
|
|
95
|
+
headerTitle: t("settings.faqs.headerTitle"),
|
|
96
|
+
}),
|
|
97
|
+
}
|
|
98
|
+
: null;
|
|
99
|
+
|
|
100
|
+
const additionalStackScreens: StackScreen[] = (additionalScreens || []).map((screen: AdditionalScreen): StackScreen => {
|
|
101
|
+
const stackScreen: any = { name: screen.name };
|
|
102
|
+
if (screen.component) stackScreen.component = screen.component;
|
|
103
|
+
if (screen.children) stackScreen.children = screen.children;
|
|
104
|
+
if (screen.options) stackScreen.options = screen.options;
|
|
105
|
+
return stackScreen as StackScreen;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const gamificationScreen: StackScreen | null = gamificationConfig?.enabled
|
|
109
|
+
? {
|
|
110
|
+
name: "Gamification",
|
|
111
|
+
options: { headerShown: false },
|
|
112
|
+
children: () => React.createElement(GamificationScreen, { config: gamificationConfig }),
|
|
113
|
+
}
|
|
114
|
+
: null;
|
|
115
|
+
|
|
116
|
+
const languageScreen: StackScreen = {
|
|
117
|
+
name: "LanguageSelection",
|
|
118
|
+
options: { headerShown: false },
|
|
119
|
+
children: () => React.createElement(LanguageSelectionScreen, {
|
|
120
|
+
headerTitle: t("settings.language.title"),
|
|
121
|
+
searchPlaceholder: t("settings.languageSelection.searchPlaceholder"),
|
|
122
|
+
}),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const accountScreen: StackScreen | null = accountConfig
|
|
126
|
+
? {
|
|
127
|
+
name: "Account",
|
|
128
|
+
options: { headerShown: false },
|
|
129
|
+
children: () => React.createElement(AccountScreen, { config: accountConfig }),
|
|
130
|
+
}
|
|
131
|
+
: null;
|
|
132
|
+
|
|
133
|
+
const allScreens: StackScreen[] = [
|
|
134
|
+
...baseScreens,
|
|
135
|
+
...(faqScreen ? [faqScreen] : []),
|
|
136
|
+
...additionalStackScreens,
|
|
137
|
+
...(gamificationScreen ? [gamificationScreen] : []),
|
|
138
|
+
languageScreen,
|
|
139
|
+
...(accountScreen ? [accountScreen] : []),
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
return allScreens;
|
|
143
|
+
}, [
|
|
144
|
+
t,
|
|
145
|
+
showHeader,
|
|
146
|
+
showCloseButton,
|
|
147
|
+
onClose,
|
|
148
|
+
config,
|
|
149
|
+
appInfo.version,
|
|
150
|
+
showUserProfile,
|
|
151
|
+
userProfile,
|
|
152
|
+
devSettings,
|
|
153
|
+
customSections,
|
|
154
|
+
aboutConfig,
|
|
155
|
+
legalProps,
|
|
156
|
+
notificationTranslations,
|
|
157
|
+
quietHoursTranslations,
|
|
158
|
+
faqData,
|
|
159
|
+
additionalScreens,
|
|
160
|
+
gamificationConfig,
|
|
161
|
+
accountConfig,
|
|
162
|
+
]);
|
|
163
|
+
};
|
|
@@ -6,12 +6,10 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import {
|
|
8
8
|
ScreenLayout,
|
|
9
|
-
useAppNavigation,
|
|
10
9
|
} from "@umituz/react-native-design-system";
|
|
10
|
+
import { useSettingsScreen } from "./hooks/useSettingsScreen";
|
|
11
11
|
import { SettingsHeader } from "./components/SettingsHeader";
|
|
12
12
|
import { SettingsContent } from "./components/SettingsContent";
|
|
13
|
-
import { normalizeSettingsConfig } from "./utils/normalizeConfig";
|
|
14
|
-
import { useFeatureDetection } from "./hooks/useFeatureDetection";
|
|
15
13
|
import type { SettingsConfig, CustomSettingsSection } from "./types";
|
|
16
14
|
import type { DevSettingsProps } from "../../domains/dev";
|
|
17
15
|
|
|
@@ -55,63 +53,44 @@ export interface SettingsScreenProps {
|
|
|
55
53
|
showHeader?: boolean;
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
56
|
+
export const SettingsScreen: React.FC<SettingsScreenProps> = (props) => {
|
|
57
|
+
const {
|
|
58
|
+
children,
|
|
59
|
+
config = {},
|
|
60
|
+
showUserProfile,
|
|
61
|
+
userProfile,
|
|
62
|
+
showFooter = true,
|
|
63
|
+
footerText,
|
|
64
|
+
appVersion: providedVersion,
|
|
65
|
+
customSections = [],
|
|
66
|
+
showCloseButton = false,
|
|
67
|
+
showHeader = true,
|
|
68
|
+
onClose,
|
|
69
|
+
featureOptions,
|
|
70
|
+
devSettings,
|
|
71
|
+
gamificationConfig,
|
|
72
|
+
} = props;
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
// Determine if user profile should be shown (explicit prop takes priority, then config)
|
|
92
|
-
const shouldShowUserProfile = showUserProfile ?? features.userProfile;
|
|
74
|
+
const {
|
|
75
|
+
normalizedConfig,
|
|
76
|
+
features,
|
|
77
|
+
shouldShowUserProfile,
|
|
78
|
+
appVersion,
|
|
79
|
+
handleClose,
|
|
80
|
+
} = useSettingsScreen({
|
|
81
|
+
config,
|
|
82
|
+
showUserProfile,
|
|
83
|
+
featureOptions,
|
|
84
|
+
appVersion: providedVersion,
|
|
85
|
+
onClose,
|
|
86
|
+
});
|
|
93
87
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{children ?? (
|
|
98
|
-
<SettingsContent
|
|
99
|
-
normalizedConfig={normalizedConfig}
|
|
100
|
-
features={features}
|
|
101
|
-
showUserProfile={shouldShowUserProfile}
|
|
102
|
-
userProfile={userProfile}
|
|
103
|
-
showFooter={showFooter}
|
|
104
|
-
footerText={footerText}
|
|
105
|
-
appVersion={appVersion}
|
|
106
|
-
customSections={customSections}
|
|
107
|
-
devSettings={devSettings}
|
|
108
|
-
gamificationConfig={gamificationConfig}
|
|
109
|
-
/>
|
|
110
|
-
)}
|
|
111
|
-
</ScreenLayout>;
|
|
112
|
-
}
|
|
88
|
+
const header = showHeader ? (
|
|
89
|
+
<SettingsHeader showCloseButton={showCloseButton} onClose={handleClose} />
|
|
90
|
+
) : undefined;
|
|
113
91
|
|
|
114
|
-
return
|
|
92
|
+
return (
|
|
93
|
+
<ScreenLayout header={header}>
|
|
115
94
|
{children ?? (
|
|
116
95
|
<SettingsContent
|
|
117
96
|
normalizedConfig={normalizedConfig}
|
|
@@ -126,5 +105,6 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|
|
126
105
|
gamificationConfig={gamificationConfig}
|
|
127
106
|
/>
|
|
128
107
|
)}
|
|
129
|
-
|
|
108
|
+
</ScreenLayout>
|
|
109
|
+
);
|
|
130
110
|
};
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Settings Header Component
|
|
3
|
-
* Handles close button functionality
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import React from "react";
|
|
7
|
-
import {
|
|
8
|
-
import { useAppDesignTokens, AtomicIcon,
|
|
2
|
+
import { Pressable } from "react-native";
|
|
3
|
+
import { useAppDesignTokens, AtomicIcon, useAppNavigation, NavigationHeader } from "@umituz/react-native-design-system";
|
|
9
4
|
import { useLocalization } from "../../../domains/localization";
|
|
10
5
|
|
|
11
6
|
interface SettingsHeaderProps {
|
|
@@ -29,41 +24,32 @@ export const SettingsHeader: React.FC<SettingsHeaderProps> = ({
|
|
|
29
24
|
}
|
|
30
25
|
};
|
|
31
26
|
|
|
27
|
+
const rightElement = showCloseButton ? (
|
|
28
|
+
<Pressable
|
|
29
|
+
onPress={handleClose}
|
|
30
|
+
style={({ pressed }) => [
|
|
31
|
+
{
|
|
32
|
+
width: 44,
|
|
33
|
+
height: 44,
|
|
34
|
+
justifyContent: "center",
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
backgroundColor: pressed ? tokens.colors.surfaceVariant : tokens.colors.surface,
|
|
37
|
+
borderRadius: tokens.borders.radius.full,
|
|
38
|
+
},
|
|
39
|
+
]}
|
|
40
|
+
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
41
|
+
>
|
|
42
|
+
<AtomicIcon name="close-outline" size="lg" color="textPrimary" />
|
|
43
|
+
</Pressable>
|
|
44
|
+
) : undefined;
|
|
45
|
+
|
|
32
46
|
return (
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
{showCloseButton
|
|
39
|
-
|
|
40
|
-
onPress={handleClose}
|
|
41
|
-
style={({ pressed }) => [
|
|
42
|
-
styles.closeButton,
|
|
43
|
-
{
|
|
44
|
-
backgroundColor: pressed ? tokens.colors.surfaceVariant : tokens.colors.surface,
|
|
45
|
-
borderRadius: tokens.borders.radius.full,
|
|
46
|
-
},
|
|
47
|
-
]}
|
|
48
|
-
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
49
|
-
>
|
|
50
|
-
<AtomicIcon name="close-outline" size="lg" color="textPrimary" />
|
|
51
|
-
</Pressable>
|
|
52
|
-
)}
|
|
53
|
-
</View>
|
|
47
|
+
<NavigationHeader
|
|
48
|
+
title={t('settings.title')}
|
|
49
|
+
rightElement={rightElement}
|
|
50
|
+
// If NOT showing close button, we might want a back button?
|
|
51
|
+
// But usually Settings is a root screen in a modal or stack.
|
|
52
|
+
onBackPress={!showCloseButton ? handleClose : undefined}
|
|
53
|
+
/>
|
|
54
54
|
);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const styles = StyleSheet.create({
|
|
58
|
-
container: {
|
|
59
|
-
flexDirection: 'row',
|
|
60
|
-
justifyContent: 'space-between',
|
|
61
|
-
alignItems: 'center',
|
|
62
|
-
},
|
|
63
|
-
closeButton: {
|
|
64
|
-
width: 44,
|
|
65
|
-
height: 44,
|
|
66
|
-
justifyContent: "center",
|
|
67
|
-
alignItems: "center",
|
|
68
|
-
},
|
|
69
|
-
});
|
|
55
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSettingsScreen Hook
|
|
3
|
+
* Refactored: Extracted business logic from SettingsScreen component
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useMemo, useCallback } from "react";
|
|
7
|
+
import { useAppNavigation } from "@umituz/react-native-design-system";
|
|
8
|
+
import { normalizeSettingsConfig } from "../utils/normalizeConfig";
|
|
9
|
+
import { useFeatureDetection } from "./useFeatureDetection";
|
|
10
|
+
import { getAppVersion } from "../../../utils/appUtils";
|
|
11
|
+
import type { SettingsConfig } from "../types";
|
|
12
|
+
|
|
13
|
+
export interface UseSettingsScreenParams {
|
|
14
|
+
config?: SettingsConfig;
|
|
15
|
+
showUserProfile?: boolean;
|
|
16
|
+
featureOptions?: {
|
|
17
|
+
notificationServiceAvailable?: boolean;
|
|
18
|
+
};
|
|
19
|
+
appVersion?: string;
|
|
20
|
+
onClose?: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useSettingsScreen({
|
|
24
|
+
config = {},
|
|
25
|
+
showUserProfile,
|
|
26
|
+
featureOptions,
|
|
27
|
+
appVersion: providedVersion,
|
|
28
|
+
onClose,
|
|
29
|
+
}: UseSettingsScreenParams) {
|
|
30
|
+
const navigation = useAppNavigation();
|
|
31
|
+
|
|
32
|
+
// Normalize config
|
|
33
|
+
const normalizedConfig = useMemo(
|
|
34
|
+
() => normalizeSettingsConfig(config),
|
|
35
|
+
[config]
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Feature detection
|
|
39
|
+
const features = useFeatureDetection(
|
|
40
|
+
normalizedConfig,
|
|
41
|
+
navigation,
|
|
42
|
+
featureOptions
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const shouldShowUserProfile = showUserProfile ?? features.userProfile;
|
|
46
|
+
|
|
47
|
+
const appVersion = providedVersion || getAppVersion();
|
|
48
|
+
|
|
49
|
+
const handleClose = useCallback(() => {
|
|
50
|
+
if (onClose) {
|
|
51
|
+
onClose();
|
|
52
|
+
} else {
|
|
53
|
+
navigation.goBack();
|
|
54
|
+
}
|
|
55
|
+
}, [onClose, navigation]);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
normalizedConfig,
|
|
59
|
+
features,
|
|
60
|
+
shouldShowUserProfile,
|
|
61
|
+
appVersion,
|
|
62
|
+
handleClose,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App and Platform Utilities
|
|
3
|
+
*/
|
|
4
|
+
import { Platform } from "react-native";
|
|
5
|
+
import Constants from "expo-constants";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Gets the current app version from Expo constants
|
|
9
|
+
*/
|
|
10
|
+
export function getAppVersion(): string {
|
|
11
|
+
const version = Constants.expoConfig?.version ?? Constants.manifest2?.extra?.expoClient?.version;
|
|
12
|
+
if (!version) {
|
|
13
|
+
// Return a default if not found
|
|
14
|
+
return "1.0.0";
|
|
15
|
+
}
|
|
16
|
+
return version;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Gets the current build number from Expo constants
|
|
21
|
+
*/
|
|
22
|
+
export function getBuildNumber(): string | undefined {
|
|
23
|
+
return Constants.expoConfig?.ios?.buildNumber ?? Constants.expoConfig?.android?.versionCode?.toString();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Validates if the current platform is supported
|
|
28
|
+
*/
|
|
29
|
+
export function validatePlatform(): "ios" | "android" {
|
|
30
|
+
const platform = Platform.OS;
|
|
31
|
+
if (platform !== "ios" && platform !== "android") {
|
|
32
|
+
// Default to android for consistency if something goes wrong in detection
|
|
33
|
+
return "android";
|
|
34
|
+
}
|
|
35
|
+
return platform;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Checks if the app is currently in development mode
|
|
40
|
+
*/
|
|
41
|
+
export function isDev(): boolean {
|
|
42
|
+
return __DEV__;
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./appUtils";
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AboutScreen Container Component
|
|
3
|
-
* Handles business logic and state management for About screen
|
|
4
|
-
*/
|
|
5
|
-
import React from 'react';
|
|
6
|
-
import { View, StyleSheet } from 'react-native';
|
|
7
|
-
import { AboutScreenContent } from './AboutScreenContent';
|
|
8
|
-
import { useAboutInfo } from '../hooks/useAboutInfo';
|
|
9
|
-
import { useAppDesignTokens, AtomicText, type DesignTokens } from '@umituz/react-native-design-system';
|
|
10
|
-
import type { AboutScreenProps } from './AboutScreen';
|
|
11
|
-
|
|
12
|
-
export const AboutScreenContainer: React.FC<AboutScreenProps> = ({
|
|
13
|
-
config,
|
|
14
|
-
containerStyle,
|
|
15
|
-
headerStyle,
|
|
16
|
-
titleStyle,
|
|
17
|
-
versionStyle,
|
|
18
|
-
showHeader = true,
|
|
19
|
-
headerComponent,
|
|
20
|
-
footerComponent,
|
|
21
|
-
testID,
|
|
22
|
-
}) => {
|
|
23
|
-
const tokens = useAppDesignTokens();
|
|
24
|
-
const styles = getStyles(tokens);
|
|
25
|
-
|
|
26
|
-
const { appInfo, loading, error } = useAboutInfo({
|
|
27
|
-
autoInit: true,
|
|
28
|
-
initialConfig: config,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
const containerStyles = React.useMemo(() => {
|
|
32
|
-
return [
|
|
33
|
-
styles.container,
|
|
34
|
-
{ backgroundColor: tokens.colors.backgroundPrimary },
|
|
35
|
-
containerStyle
|
|
36
|
-
];
|
|
37
|
-
}, [containerStyle, tokens.colors.backgroundPrimary, styles]);
|
|
38
|
-
|
|
39
|
-
const texts = config.texts || {};
|
|
40
|
-
|
|
41
|
-
if (loading) {
|
|
42
|
-
return (
|
|
43
|
-
<View style={containerStyles} testID={testID}>
|
|
44
|
-
<AtomicText
|
|
45
|
-
type="bodyMedium"
|
|
46
|
-
color="textSecondary"
|
|
47
|
-
style={styles.statusText}
|
|
48
|
-
>
|
|
49
|
-
{texts.loading}
|
|
50
|
-
</AtomicText>
|
|
51
|
-
</View>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (error) {
|
|
56
|
-
return (
|
|
57
|
-
<View style={containerStyles} testID={testID}>
|
|
58
|
-
<AtomicText
|
|
59
|
-
type="bodyMedium"
|
|
60
|
-
color="error"
|
|
61
|
-
style={styles.statusText}
|
|
62
|
-
>
|
|
63
|
-
{texts.errorPrefix} {error}
|
|
64
|
-
</AtomicText>
|
|
65
|
-
</View>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!appInfo) {
|
|
70
|
-
return (
|
|
71
|
-
<View style={containerStyles} testID={testID}>
|
|
72
|
-
<AtomicText
|
|
73
|
-
type="bodyMedium"
|
|
74
|
-
color="textSecondary"
|
|
75
|
-
style={styles.statusText}
|
|
76
|
-
>
|
|
77
|
-
{texts.noInfo}
|
|
78
|
-
</AtomicText>
|
|
79
|
-
</View>
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<AboutScreenContent
|
|
85
|
-
appInfo={appInfo}
|
|
86
|
-
config={config}
|
|
87
|
-
containerStyle={containerStyle}
|
|
88
|
-
headerStyle={headerStyle}
|
|
89
|
-
titleStyle={titleStyle}
|
|
90
|
-
versionStyle={versionStyle}
|
|
91
|
-
showHeader={showHeader}
|
|
92
|
-
headerComponent={headerComponent}
|
|
93
|
-
footerComponent={footerComponent}
|
|
94
|
-
testID={testID}
|
|
95
|
-
_tokens={tokens}
|
|
96
|
-
/>
|
|
97
|
-
);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const getStyles = (tokens: DesignTokens) => StyleSheet.create({
|
|
101
|
-
container: {
|
|
102
|
-
flex: 1,
|
|
103
|
-
},
|
|
104
|
-
statusText: {
|
|
105
|
-
textAlign: 'center',
|
|
106
|
-
fontSize: tokens.typography.bodyMedium.responsiveFontSize,
|
|
107
|
-
marginTop: 20,
|
|
108
|
-
},
|
|
109
|
-
});
|