@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "5.4.12",
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: Record<string, string> = {
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" },