@umituz/react-native-settings 5.4.12 → 5.4.13
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/appearance/presentation/screens/AppearanceScreen.tsx +4 -0
- package/src/domains/faqs/presentation/screens/FAQScreen.tsx +7 -3
- package/src/domains/feedback/presentation/screens/FeatureRequestScreen.tsx +8 -9
- package/src/domains/localization/presentation/components/LanguageItem.tsx +2 -2
- package/src/domains/notifications/reminders/presentation/components/ReminderItem.tsx +2 -2
- package/src/domains/video-tutorials/presentation/components/VideoTutorialCard.tsx +10 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-settings",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.13",
|
|
4
4
|
"description": "Complete settings hub for React Native apps - consolidated package with settings, localization, about, legal, appearance, feedback, FAQs, rating, and gamification - expo-store-review and expo-device now lazy loaded",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -197,6 +197,10 @@ export const AppearanceScreen: React.FC<AppearanceScreenProps> = ({
|
|
|
197
197
|
contentContainerStyle={{
|
|
198
198
|
paddingBottom: tokens.spacing['2xl'],
|
|
199
199
|
}}
|
|
200
|
+
removeClippedSubviews={true}
|
|
201
|
+
maxToRenderPerBatch={5}
|
|
202
|
+
windowSize={3}
|
|
203
|
+
initialNumToRender={3}
|
|
200
204
|
/>
|
|
201
205
|
</ScreenLayout>
|
|
202
206
|
);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Uses design system tokens for theming
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React, { useMemo } from 'react';
|
|
7
|
+
import React, { useMemo, useCallback } from 'react';
|
|
8
8
|
import { View, StyleSheet, ViewStyle, TextStyle, useWindowDimensions, FlatList } from 'react-native';
|
|
9
9
|
import { getContentMaxWidth } from '@umituz/react-native-design-system/device';
|
|
10
10
|
import { ScreenLayout } from '@umituz/react-native-design-system/layouts';
|
|
@@ -102,7 +102,7 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
102
102
|
</View>
|
|
103
103
|
), [searchQuery, hasResults, searchPlaceholder, emptySearchTitle, emptySearchMessage, customStyles, tokens, contentMaxWidth]);
|
|
104
104
|
|
|
105
|
-
const renderCategory = ({ item }: { item: FAQCategory }) => (
|
|
105
|
+
const renderCategory = useCallback(({ item }: { item: FAQCategory }) => (
|
|
106
106
|
<View style={{ alignSelf: 'center', width: '100%', maxWidth: contentMaxWidth }}>
|
|
107
107
|
<FAQCategoryComponent
|
|
108
108
|
category={item}
|
|
@@ -111,7 +111,7 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
111
111
|
styles={customStyles?.category}
|
|
112
112
|
/>
|
|
113
113
|
</View>
|
|
114
|
-
);
|
|
114
|
+
), [contentMaxWidth, isExpanded, toggleExpansion, customStyles?.category]);
|
|
115
115
|
|
|
116
116
|
return (
|
|
117
117
|
<ScreenLayout
|
|
@@ -128,6 +128,10 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
128
128
|
ListFooterComponent={<View style={styles.footer} />}
|
|
129
129
|
showsVerticalScrollIndicator={false}
|
|
130
130
|
contentContainerStyle={{ paddingBottom: tokens.spacing.xl }}
|
|
131
|
+
removeClippedSubviews={true}
|
|
132
|
+
maxToRenderPerBatch={10}
|
|
133
|
+
windowSize={5}
|
|
134
|
+
initialNumToRender={8}
|
|
131
135
|
/>
|
|
132
136
|
</ScreenLayout>
|
|
133
137
|
);
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
} from "@umituz/react-native-design-system/atoms";
|
|
13
13
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
14
14
|
import { useAppNavigation } from "@umituz/react-native-design-system/molecules";
|
|
15
|
-
import { devWarn } from "../../../../utils/devUtils";
|
|
16
15
|
import { ScreenLayout } from "@umituz/react-native-design-system/layouts";
|
|
17
16
|
import { ICON_PATHS } from "../../../../utils/iconPaths";
|
|
18
17
|
import { useFeatureRequests } from "../../infrastructure/useFeatureRequests";
|
|
@@ -30,7 +29,7 @@ interface FeatureRequestScreenProps {
|
|
|
30
29
|
export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ config, texts }) => {
|
|
31
30
|
const tokens = useAppDesignTokens();
|
|
32
31
|
const navigation = useAppNavigation();
|
|
33
|
-
const { requests, userVotes, isLoading, vote, submitRequest, userId } = useFeatureRequests();
|
|
32
|
+
const { requests, userVotes, isLoading, vote, submitRequest: _submitRequest, userId } = useFeatureRequests();
|
|
34
33
|
|
|
35
34
|
const [activeTab, setActiveTab] = useState<'all' | 'my' | 'roadmap'>('all');
|
|
36
35
|
|
|
@@ -41,21 +40,21 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
41
40
|
const bannerSub = t.banner?.subtitle || `${requests.length} feature requests`;
|
|
42
41
|
const newIdeaLabel = t.new_idea || "NEW IDEA?";
|
|
43
42
|
|
|
44
|
-
const tabLabels = {
|
|
43
|
+
const tabLabels = useMemo(() => ({
|
|
45
44
|
all: t.tabs?.all || "All Requests",
|
|
46
45
|
my: t.tabs?.my || "My Feedback",
|
|
47
46
|
roadmap: t.tabs?.roadmap || "Roadmap",
|
|
48
|
-
};
|
|
47
|
+
}), [t.tabs?.all, t.tabs?.my, t.tabs?.roadmap]);
|
|
49
48
|
|
|
50
|
-
const statusLabels
|
|
49
|
+
const statusLabels = useMemo(() => ({
|
|
51
50
|
planned: t.status?.planned || "Planned",
|
|
52
51
|
review: t.status?.review || "Under Review",
|
|
53
52
|
completed: t.status?.completed || "Completed",
|
|
54
53
|
pending: t.status?.pending || "Pending",
|
|
55
54
|
dismissed: t.status?.dismissed || "Dismissed",
|
|
56
|
-
};
|
|
55
|
+
}), [t.status?.planned, t.status?.review, t.status?.completed, t.status?.pending, t.status?.dismissed]);
|
|
57
56
|
|
|
58
|
-
const getStatusColor = (status: string) => {
|
|
57
|
+
const getStatusColor = useCallback((status: string) => {
|
|
59
58
|
switch (status) {
|
|
60
59
|
case 'planned': return '#3b82f6';
|
|
61
60
|
case 'review': return '#f59e0b';
|
|
@@ -64,7 +63,7 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
64
63
|
case 'dismissed': return '#ef4444';
|
|
65
64
|
default: return tokens.colors.textSecondary;
|
|
66
65
|
}
|
|
67
|
-
};
|
|
66
|
+
}, [tokens.colors.textSecondary]);
|
|
68
67
|
|
|
69
68
|
const filteredRequests = useMemo(() => {
|
|
70
69
|
switch (activeTab) {
|
|
@@ -127,7 +126,7 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
127
126
|
</View>
|
|
128
127
|
</View>
|
|
129
128
|
);
|
|
130
|
-
}, [userVotes, vote, tokens.colors, getStatusColor, statusLabels, t]);
|
|
129
|
+
}, [userVotes, vote, tokens.colors, getStatusColor, statusLabels, t.comment_count]);
|
|
131
130
|
|
|
132
131
|
const tabs = useMemo(() => (['all', 'my', 'roadmap'] as const), []);
|
|
133
132
|
|
|
@@ -35,7 +35,7 @@ interface LanguageItemProps {
|
|
|
35
35
|
// SVG path for checkmark icon (works without external icon library)
|
|
36
36
|
const CHECKMARK_PATH = "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z";
|
|
37
37
|
|
|
38
|
-
export const LanguageItem: React.FC<LanguageItemProps> = ({
|
|
38
|
+
export const LanguageItem: React.FC<LanguageItemProps> = React.memo(({
|
|
39
39
|
item,
|
|
40
40
|
isSelected,
|
|
41
41
|
onSelect,
|
|
@@ -135,5 +135,5 @@ export const LanguageItem: React.FC<LanguageItemProps> = ({
|
|
|
135
135
|
)}
|
|
136
136
|
</TouchableOpacity>
|
|
137
137
|
);
|
|
138
|
-
};
|
|
138
|
+
});
|
|
139
139
|
|
|
@@ -39,7 +39,7 @@ const getFrequencyIcon = (frequency: ReminderFrequency): string => {
|
|
|
39
39
|
return icons[frequency] || 'notifications';
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
export const ReminderItem: React.FC<ReminderItemProps> = ({
|
|
42
|
+
export const ReminderItem: React.FC<ReminderItemProps> = React.memo(({
|
|
43
43
|
reminder,
|
|
44
44
|
translations,
|
|
45
45
|
onToggle,
|
|
@@ -97,7 +97,7 @@ export const ReminderItem: React.FC<ReminderItemProps> = ({
|
|
|
97
97
|
</View>
|
|
98
98
|
</View>
|
|
99
99
|
);
|
|
100
|
-
};
|
|
100
|
+
});
|
|
101
101
|
|
|
102
102
|
const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
|
|
103
103
|
StyleSheet.create({
|
|
@@ -3,31 +3,31 @@
|
|
|
3
3
|
* Single Responsibility: Display individual video tutorial card
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React from "react";
|
|
6
|
+
import React, { useMemo } from "react";
|
|
7
7
|
import { View, Image, StyleSheet, TouchableOpacity } from "react-native";
|
|
8
8
|
import { AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
10
|
import type { VideoTutorial } from "../../types";
|
|
11
11
|
|
|
12
|
+
const formatDuration = (seconds: number): string => {
|
|
13
|
+
const minutes = Math.floor(seconds / 60);
|
|
14
|
+
const remainingSeconds = seconds % 60;
|
|
15
|
+
return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`;
|
|
16
|
+
};
|
|
17
|
+
|
|
12
18
|
interface VideoTutorialCardProps {
|
|
13
19
|
readonly tutorial: VideoTutorial;
|
|
14
20
|
readonly onPress: () => void;
|
|
15
21
|
readonly horizontal?: boolean;
|
|
16
22
|
}
|
|
17
23
|
|
|
18
|
-
export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
|
|
24
|
+
export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = React.memo(({
|
|
19
25
|
tutorial,
|
|
20
26
|
onPress,
|
|
21
27
|
horizontal = false,
|
|
22
28
|
}) => {
|
|
23
29
|
const tokens = useAppDesignTokens();
|
|
24
|
-
const styles = getStyles(tokens);
|
|
25
|
-
|
|
26
|
-
const formatDuration = (seconds: number): string => {
|
|
27
|
-
const minutes = Math.floor(seconds / 60);
|
|
28
|
-
const remainingSeconds = seconds % 60;
|
|
29
|
-
return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`;
|
|
30
|
-
};
|
|
30
|
+
const styles = useMemo(() => getStyles(tokens), [tokens]);
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<TouchableOpacity
|
|
@@ -84,7 +84,7 @@ export const VideoTutorialCard: React.FC<VideoTutorialCardProps> = ({
|
|
|
84
84
|
</View>
|
|
85
85
|
</TouchableOpacity>
|
|
86
86
|
);
|
|
87
|
-
};
|
|
87
|
+
});
|
|
88
88
|
|
|
89
89
|
const getStyles = (tokens: ReturnType<typeof useAppDesignTokens>) => StyleSheet.create({
|
|
90
90
|
container: { borderRadius: 12, borderWidth: 1, marginBottom: 12, overflow: "hidden" },
|