@umituz/react-native-settings 5.3.75 → 5.3.77
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/dist/utils/iconPaths.d.ts +40 -0
- package/package.json +1 -1
- package/src/domains/appearance/presentation/components/ColorPicker.tsx +6 -1
- package/src/domains/faqs/presentation/components/FAQItem.tsx +7 -3
- package/src/domains/faqs/presentation/components/FAQSearchBar.tsx +6 -1
- package/src/domains/faqs/presentation/screens/FAQScreen.tsx +50 -35
- package/src/domains/feedback/presentation/screens/FeatureRequestScreen.tsx +68 -36
- package/src/domains/notifications/reminders/presentation/screens/ReminderListScreen.tsx +53 -29
- package/src/utils/iconPaths.ts +59 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common Icon SVG Paths
|
|
3
|
+
*
|
|
4
|
+
* Centralized SVG paths for frequently used icons
|
|
5
|
+
* Works without external icon libraries
|
|
6
|
+
*/
|
|
7
|
+
export declare const ICON_PATHS: {
|
|
8
|
+
readonly 'chevron-up': "M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z";
|
|
9
|
+
readonly 'chevron-down': "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z";
|
|
10
|
+
readonly 'chevron-forward': "M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z";
|
|
11
|
+
readonly 'chevron-back': "M15.41 7.41L10.83 12l4.58 4.59L14 18l-6-6 6-6z";
|
|
12
|
+
readonly 'arrow-right': "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z";
|
|
13
|
+
readonly 'arrow-forward': "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z";
|
|
14
|
+
readonly 'arrow-left': "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z";
|
|
15
|
+
readonly close: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z";
|
|
16
|
+
readonly checkmark: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z";
|
|
17
|
+
readonly 'checkmark-circle': "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";
|
|
18
|
+
readonly plus: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z";
|
|
19
|
+
readonly search: "M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z";
|
|
20
|
+
readonly star: "M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z";
|
|
21
|
+
readonly 'alert-circle': "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z";
|
|
22
|
+
readonly 'information-circle': "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z";
|
|
23
|
+
readonly warning: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z";
|
|
24
|
+
readonly 'chatbubble-outline': "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z";
|
|
25
|
+
readonly mail: "M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z";
|
|
26
|
+
readonly time: "M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z";
|
|
27
|
+
readonly moon: "M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z";
|
|
28
|
+
readonly users: "M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z";
|
|
29
|
+
readonly person: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z";
|
|
30
|
+
readonly create: "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z";
|
|
31
|
+
readonly trash: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z";
|
|
32
|
+
readonly share: "M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z";
|
|
33
|
+
readonly globe: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z";
|
|
34
|
+
readonly settings: "M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z";
|
|
35
|
+
readonly heart: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z";
|
|
36
|
+
readonly 'heart-outline': "M16.5 3c-1.74 0-3.41.81-4.5 2.09C10.91 3.81 9.24 3 7.5 3 4.42 3 2 5.42 2 8.5c0 3.78 3.4 6.86 8.55 11.54L12 21.35l1.45-1.32C18.6 15.36 22 12.28 22 8.5 22 5.42 19.58 3 16.5 3zm-4.4 15.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z";
|
|
37
|
+
readonly notifications: "M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z";
|
|
38
|
+
readonly 'notifications-off': "M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm0-18c.83 0 1.5.67 1.5 1.5 0 .24-.05.46-.14.67l.94.94C14.74 6.57 15 5.82 15 5c0-1.66-1.34-3-3-3-.82 0-1.57.26-2.18.69l.95.95c.2-.09.43-.14.67-.14zM2.81 2.81L1.39 4.22l2.68 2.68C3.06 8.08 2.38 9.5 2.12 11H4.14c.24-1.12.76-2.13 1.48-2.96l1.94 1.94c-.06.34-.1.69-.1 1.02 0 2.48 1.51 4.5 4 4.5.33 0 .68-.04 1.02-.1l4.23 4.23c-.66.32-1.39.51-2.17.51-2.48 0-4.5-2.02-4.5-4.5h-2c0 2.93 1.81 5.45 4.38 6.51l2.5 2.5 1.41-1.41L2.81 2.81z";
|
|
39
|
+
};
|
|
40
|
+
export type IconPathName = keyof typeof ICON_PATHS;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-settings",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.77",
|
|
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",
|
|
@@ -10,6 +10,7 @@ import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
|
10
10
|
import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
11
11
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
12
12
|
import { isDev } from "../../../../utils/devUtils";
|
|
13
|
+
import { ICON_PATHS } from "../../../../utils/iconPaths";
|
|
13
14
|
|
|
14
15
|
interface ColorPickerProps {
|
|
15
16
|
label: string;
|
|
@@ -64,7 +65,11 @@ export const ColorPicker: React.FC<ColorPickerProps> = ({
|
|
|
64
65
|
accessibilityHint={`Select ${color} color`}
|
|
65
66
|
>
|
|
66
67
|
{isSelected && (
|
|
67
|
-
<AtomicIcon
|
|
68
|
+
<AtomicIcon
|
|
69
|
+
svgPath={ICON_PATHS['checkmark']}
|
|
70
|
+
customSize={16}
|
|
71
|
+
customColor={tokens.colors.textInverse}
|
|
72
|
+
/>
|
|
68
73
|
)}
|
|
69
74
|
</TouchableOpacity>
|
|
70
75
|
);
|
|
@@ -27,6 +27,10 @@ export interface FAQItemProps {
|
|
|
27
27
|
styles?: FAQItemStyles;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
// SVG paths for chevron icons
|
|
31
|
+
const CHEVRON_UP_PATH = "M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z";
|
|
32
|
+
const CHEVRON_DOWN_PATH = "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z";
|
|
33
|
+
|
|
30
34
|
export const FAQItemComponent: React.FC<FAQItemProps> = React.memo(({
|
|
31
35
|
item,
|
|
32
36
|
isExpanded,
|
|
@@ -96,9 +100,9 @@ export const FAQItemComponent: React.FC<FAQItemProps> = React.memo(({
|
|
|
96
100
|
</View>
|
|
97
101
|
<View style={styles.iconContainer}>
|
|
98
102
|
<AtomicIcon
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
svgPath={isExpanded ? CHEVRON_UP_PATH : CHEVRON_DOWN_PATH}
|
|
104
|
+
customSize={20}
|
|
105
|
+
customColor={isExpanded ? tokens.colors.onPrimary : tokens.colors.secondary}
|
|
102
106
|
/>
|
|
103
107
|
</View>
|
|
104
108
|
</TouchableOpacity>
|
|
@@ -8,6 +8,7 @@ import React, { useMemo } from 'react';
|
|
|
8
8
|
import { View, TextInput, StyleSheet, ViewStyle, TextStyle } from 'react-native';
|
|
9
9
|
import { AtomicIcon } from '@umituz/react-native-design-system/atoms';
|
|
10
10
|
import { useAppDesignTokens } from '@umituz/react-native-design-system/theme';
|
|
11
|
+
import { ICON_PATHS } from '../../../../utils/iconPaths';
|
|
11
12
|
|
|
12
13
|
export interface FAQSearchBarStyles {
|
|
13
14
|
container?: ViewStyle;
|
|
@@ -58,7 +59,11 @@ export const FAQSearchBar: React.FC<FAQSearchBarProps> = ({
|
|
|
58
59
|
return (
|
|
59
60
|
<View style={[styles.container, customStyles?.container]}>
|
|
60
61
|
<View style={styles.iconContainer}>
|
|
61
|
-
<AtomicIcon
|
|
62
|
+
<AtomicIcon
|
|
63
|
+
svgPath={ICON_PATHS['search']}
|
|
64
|
+
customSize={20}
|
|
65
|
+
customColor={tokens.colors.secondary}
|
|
66
|
+
/>
|
|
62
67
|
</View>
|
|
63
68
|
<TextInput
|
|
64
69
|
style={[styles.input, customStyles?.input]}
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React, { useMemo } from 'react';
|
|
8
|
-
import { View, StyleSheet, ViewStyle, TextStyle, useWindowDimensions } from 'react-native';
|
|
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';
|
|
11
|
-
import { useAppNavigation } from '@umituz/react-native-design-system/molecules';
|
|
11
|
+
import { NavigationHeader, useAppNavigation } from '@umituz/react-native-design-system/molecules';
|
|
12
12
|
import { useAppDesignTokens } from '@umituz/react-native-design-system/theme';
|
|
13
13
|
import { FAQCategory } from '../../domain/entities/FAQEntity';
|
|
14
14
|
import { useFAQSearch } from '../hooks/useFAQSearch';
|
|
@@ -43,6 +43,7 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
43
43
|
searchPlaceholder,
|
|
44
44
|
emptySearchTitle,
|
|
45
45
|
emptySearchMessage,
|
|
46
|
+
headerTitle,
|
|
46
47
|
onBack,
|
|
47
48
|
renderHeader,
|
|
48
49
|
styles: customStyles,
|
|
@@ -75,45 +76,59 @@ export const FAQScreen: React.FC<FAQScreenProps> = ({
|
|
|
75
76
|
}
|
|
76
77
|
};
|
|
77
78
|
|
|
78
|
-
const header = renderHeader ? renderHeader({ onBack: handleBack }) :
|
|
79
|
+
const header = renderHeader ? renderHeader({ onBack: handleBack }) : (
|
|
80
|
+
<NavigationHeader title={headerTitle} onBackPress={handleBack} />
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Render search bar as list header
|
|
84
|
+
const ListHeader = useMemo(() => (
|
|
85
|
+
<View style={{ alignSelf: 'center', width: '100%', maxWidth: contentMaxWidth }}>
|
|
86
|
+
<View style={[styles.searchBar, customStyles?.header]}>
|
|
87
|
+
<FAQSearchBar
|
|
88
|
+
value={searchQuery}
|
|
89
|
+
onChangeText={setSearchQuery}
|
|
90
|
+
placeholder={searchPlaceholder}
|
|
91
|
+
styles={customStyles?.searchBar}
|
|
92
|
+
/>
|
|
93
|
+
</View>
|
|
94
|
+
|
|
95
|
+
{searchQuery && !hasResults && (
|
|
96
|
+
<FAQEmptyState
|
|
97
|
+
title={emptySearchTitle}
|
|
98
|
+
message={emptySearchMessage}
|
|
99
|
+
styles={customStyles?.emptyState}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
</View>
|
|
103
|
+
), [searchQuery, hasResults, searchPlaceholder, emptySearchTitle, emptySearchMessage, customStyles, tokens, contentMaxWidth]);
|
|
104
|
+
|
|
105
|
+
const renderCategory = ({ item }: { item: FAQCategory }) => (
|
|
106
|
+
<View style={{ alignSelf: 'center', width: '100%', maxWidth: contentMaxWidth }}>
|
|
107
|
+
<FAQCategoryComponent
|
|
108
|
+
category={item}
|
|
109
|
+
isExpanded={isExpanded}
|
|
110
|
+
onToggleItem={toggleExpansion}
|
|
111
|
+
styles={customStyles?.category}
|
|
112
|
+
/>
|
|
113
|
+
</View>
|
|
114
|
+
);
|
|
79
115
|
|
|
80
116
|
return (
|
|
81
117
|
<ScreenLayout
|
|
82
118
|
edges={['top', 'bottom', 'left', 'right']}
|
|
83
|
-
scrollable={
|
|
119
|
+
scrollable={false}
|
|
84
120
|
header={header}
|
|
85
|
-
contentContainerStyle={customStyles?.content}
|
|
86
121
|
>
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{searchQuery && !hasResults ? (
|
|
98
|
-
<FAQEmptyState
|
|
99
|
-
title={emptySearchTitle}
|
|
100
|
-
message={emptySearchMessage}
|
|
101
|
-
styles={customStyles?.emptyState}
|
|
102
|
-
/>
|
|
103
|
-
) : (
|
|
104
|
-
filteredCategories.map((cat) => (
|
|
105
|
-
<FAQCategoryComponent
|
|
106
|
-
key={cat.id}
|
|
107
|
-
category={cat}
|
|
108
|
-
isExpanded={isExpanded}
|
|
109
|
-
onToggleItem={toggleExpansion}
|
|
110
|
-
styles={customStyles?.category}
|
|
111
|
-
/>
|
|
112
|
-
))
|
|
113
|
-
)}
|
|
114
|
-
|
|
115
|
-
<View style={styles.footer} />
|
|
116
|
-
</View>
|
|
122
|
+
<FlatList
|
|
123
|
+
data={filteredCategories}
|
|
124
|
+
renderItem={renderCategory}
|
|
125
|
+
keyExtractor={(item) => item.id}
|
|
126
|
+
ListHeaderComponent={hasResults ? ListHeader : null}
|
|
127
|
+
ListEmptyComponent={!hasResults ? ListHeader : null}
|
|
128
|
+
ListFooterComponent={<View style={styles.footer} />}
|
|
129
|
+
showsVerticalScrollIndicator={false}
|
|
130
|
+
contentContainerStyle={{ paddingBottom: tokens.spacing.xl }}
|
|
131
|
+
/>
|
|
117
132
|
</ScreenLayout>
|
|
118
133
|
);
|
|
119
134
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React, { useState, useCallback } from "react";
|
|
1
|
+
import React, { useState, useCallback, useMemo } from "react";
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
StyleSheet,
|
|
5
5
|
TouchableOpacity,
|
|
6
|
-
|
|
6
|
+
FlatList,
|
|
7
7
|
ActivityIndicator,
|
|
8
8
|
} from "react-native";
|
|
9
9
|
import {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
14
14
|
import { ScreenLayout } from "@umituz/react-native-design-system/layouts";
|
|
15
15
|
import { FeedbackModal } from "../components/FeedbackModal";
|
|
16
|
+
import { ICON_PATHS } from "../../../../utils/iconPaths";
|
|
16
17
|
import { useFeatureRequests } from "../../infrastructure/useFeatureRequests";
|
|
17
18
|
import type { FeedbackRating } from "../../domain/entities/FeedbackEntity";
|
|
18
19
|
import type { FeatureRequestItem } from "../../domain/entities/FeatureRequestEntity";
|
|
@@ -82,7 +83,7 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
82
83
|
}
|
|
83
84
|
};
|
|
84
85
|
|
|
85
|
-
const filteredRequests = (() => {
|
|
86
|
+
const filteredRequests = useMemo(() => {
|
|
86
87
|
switch (activeTab) {
|
|
87
88
|
case 'my':
|
|
88
89
|
return requests.filter(r => r.createdBy === userId);
|
|
@@ -91,22 +92,30 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
91
92
|
default:
|
|
92
93
|
return requests;
|
|
93
94
|
}
|
|
94
|
-
})
|
|
95
|
+
}, [requests, activeTab, userId]);
|
|
95
96
|
|
|
96
|
-
const renderRequestCard = (item: FeatureRequestItem) => {
|
|
97
|
+
const renderRequestCard = useCallback(({ item }: { item: FeatureRequestItem }) => {
|
|
97
98
|
const voted = userVotes[item.id] || null;
|
|
98
99
|
|
|
99
100
|
return (
|
|
100
101
|
<View key={item.id} style={[styles.card, { backgroundColor: tokens.colors.surfaceSecondary, borderColor: tokens.colors.borderLight }]}>
|
|
101
102
|
<View style={styles.voteColumn}>
|
|
102
103
|
<TouchableOpacity onPress={() => vote(item.id, 'up')}>
|
|
103
|
-
<AtomicIcon
|
|
104
|
+
<AtomicIcon
|
|
105
|
+
svgPath={ICON_PATHS['chevron-up']}
|
|
106
|
+
customSize={20}
|
|
107
|
+
customColor={voted === 'up' ? tokens.colors.primary : tokens.colors.textSecondary}
|
|
108
|
+
/>
|
|
104
109
|
</TouchableOpacity>
|
|
105
110
|
<AtomicText style={[styles.voteCount, { color: voted === 'up' ? tokens.colors.primary : tokens.colors.textPrimary }]}>
|
|
106
111
|
{item.votes}
|
|
107
112
|
</AtomicText>
|
|
108
113
|
<TouchableOpacity onPress={() => vote(item.id, 'down')}>
|
|
109
|
-
<AtomicIcon
|
|
114
|
+
<AtomicIcon
|
|
115
|
+
svgPath={ICON_PATHS['chevron-down']}
|
|
116
|
+
customSize={20}
|
|
117
|
+
customColor={voted === 'down' ? tokens.colors.primary : tokens.colors.textSecondary}
|
|
118
|
+
/>
|
|
110
119
|
</TouchableOpacity>
|
|
111
120
|
</View>
|
|
112
121
|
|
|
@@ -135,19 +144,27 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
135
144
|
</View>
|
|
136
145
|
</View>
|
|
137
146
|
);
|
|
138
|
-
};
|
|
147
|
+
}, [userVotes, vote, tokens.colors, getStatusColor, statusLabels, t]);
|
|
148
|
+
|
|
149
|
+
const keyExtractor = useCallback((item: FeatureRequestItem) => item.id, []);
|
|
139
150
|
|
|
140
|
-
const
|
|
151
|
+
const tabs = useMemo(() => (['all', 'my', 'roadmap'] as const), []);
|
|
152
|
+
|
|
153
|
+
const header = useMemo(() => (
|
|
141
154
|
<View style={styles.header}>
|
|
142
155
|
<AtomicText style={styles.headerTitle}>{screenTitle}</AtomicText>
|
|
143
156
|
<TouchableOpacity
|
|
144
157
|
style={[styles.addButton, { backgroundColor: tokens.colors.primary }]}
|
|
145
158
|
onPress={() => setIsModalVisible(true)}
|
|
146
159
|
>
|
|
147
|
-
<AtomicIcon
|
|
160
|
+
<AtomicIcon
|
|
161
|
+
svgPath={ICON_PATHS['plus']}
|
|
162
|
+
customSize={16}
|
|
163
|
+
customColor={tokens.colors.onPrimary}
|
|
164
|
+
/>
|
|
148
165
|
</TouchableOpacity>
|
|
149
166
|
</View>
|
|
150
|
-
);
|
|
167
|
+
), [screenTitle, tokens.colors.primary, tokens.colors.onPrimary]);
|
|
151
168
|
|
|
152
169
|
if (isLoading) {
|
|
153
170
|
return (
|
|
@@ -162,7 +179,7 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
162
179
|
return (
|
|
163
180
|
<ScreenLayout header={header} edges={['top', 'bottom']}>
|
|
164
181
|
<View style={styles.tabsContainer}>
|
|
165
|
-
{
|
|
182
|
+
{tabs.map((tab) => (
|
|
166
183
|
<TouchableOpacity
|
|
167
184
|
key={tab}
|
|
168
185
|
onPress={() => setActiveTab(tab)}
|
|
@@ -175,35 +192,50 @@ export const FeatureRequestScreen: React.FC<FeatureRequestScreenProps> = ({ conf
|
|
|
175
192
|
))}
|
|
176
193
|
</View>
|
|
177
194
|
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
195
|
+
<FlatList
|
|
196
|
+
data={filteredRequests}
|
|
197
|
+
renderItem={renderRequestCard}
|
|
198
|
+
keyExtractor={(item) => item.id}
|
|
199
|
+
ListHeaderComponent={
|
|
200
|
+
<View style={styles.container}>
|
|
201
|
+
<View style={[styles.banner, { backgroundColor: tokens.colors.primary + '10', borderColor: tokens.colors.primary + '20' }]}>
|
|
202
|
+
<View style={styles.bannerIconContainer}>
|
|
203
|
+
<AtomicIcon
|
|
204
|
+
svgPath={ICON_PATHS['users']}
|
|
205
|
+
customSize={24}
|
|
206
|
+
customColor={tokens.colors.primary}
|
|
207
|
+
/>
|
|
208
|
+
<View style={styles.pulseDot} />
|
|
209
|
+
</View>
|
|
210
|
+
<View>
|
|
211
|
+
<AtomicText style={styles.bannerTitle}>{bannerTitle}</AtomicText>
|
|
212
|
+
<AtomicText style={[styles.bannerSub, { color: tokens.colors.textSecondary }]}>
|
|
213
|
+
{bannerSub}
|
|
214
|
+
</AtomicText>
|
|
215
|
+
</View>
|
|
216
|
+
</View>
|
|
193
217
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
218
|
+
<AtomicText style={styles.sectionTitle}>{trendingTitle}</AtomicText>
|
|
219
|
+
</View>
|
|
220
|
+
}
|
|
221
|
+
ListEmptyComponent={
|
|
222
|
+
<View style={[styles.emptyState, { paddingHorizontal: tokens.spacing.md }]}>
|
|
223
|
+
<AtomicIcon
|
|
224
|
+
svgPath={ICON_PATHS['chatbubble-outline']}
|
|
225
|
+
customSize={32}
|
|
226
|
+
customColor={tokens.colors.textTertiary}
|
|
227
|
+
/>
|
|
197
228
|
<AtomicText style={[styles.emptyText, { color: tokens.colors.textTertiary }]}>
|
|
198
229
|
{t.empty || "No requests yet. Be the first!"}
|
|
199
230
|
</AtomicText>
|
|
200
231
|
</View>
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
232
|
+
}
|
|
233
|
+
contentContainerStyle={styles.listContent}
|
|
234
|
+
showsVerticalScrollIndicator={false}
|
|
235
|
+
removeClippedSubviews={true}
|
|
236
|
+
maxToRenderPerBatch={10}
|
|
237
|
+
windowSize={5}
|
|
238
|
+
/>
|
|
207
239
|
|
|
208
240
|
{isModalVisible && (
|
|
209
241
|
<FeedbackModal
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React, { useMemo, useCallback } from 'react';
|
|
7
|
-
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
|
7
|
+
import { View, StyleSheet, TouchableOpacity, FlatList } from 'react-native';
|
|
8
8
|
import { AtomicText, AtomicIcon, AtomicSpinner } from '@umituz/react-native-design-system/atoms';
|
|
9
9
|
import { ScreenLayout } from '@umituz/react-native-design-system/layouts';
|
|
10
10
|
import { useAppDesignTokens } from '@umituz/react-native-design-system/theme';
|
|
@@ -54,10 +54,45 @@ export const ReminderListScreen: React.FC<ReminderListScreenProps> = ({
|
|
|
54
54
|
|
|
55
55
|
const fab = canAddMore ? (
|
|
56
56
|
<TouchableOpacity style={styles.fab} onPress={onAddPress} activeOpacity={0.8}>
|
|
57
|
-
<AtomicIcon
|
|
57
|
+
<AtomicIcon
|
|
58
|
+
svgPath="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"
|
|
59
|
+
customSize={20}
|
|
60
|
+
customColor={tokens.colors.onPrimary}
|
|
61
|
+
/>
|
|
58
62
|
<AtomicText type="bodyMedium" style={styles.fabText}>{translations.addButtonLabel}</AtomicText>
|
|
59
63
|
</TouchableOpacity>
|
|
60
|
-
) :
|
|
64
|
+
) : null;
|
|
65
|
+
|
|
66
|
+
const renderEmptyState = useCallback(() => (
|
|
67
|
+
<View style={styles.emptyContainer}>
|
|
68
|
+
<View style={styles.emptyIconContainer}>
|
|
69
|
+
<AtomicIcon
|
|
70
|
+
svgPath="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm0-14c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 18c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"
|
|
71
|
+
customSize={48}
|
|
72
|
+
customColor={tokens.colors.secondary}
|
|
73
|
+
/>
|
|
74
|
+
</View>
|
|
75
|
+
<AtomicText type="bodyLarge" style={styles.emptyTitle}>{translations.emptyTitle}</AtomicText>
|
|
76
|
+
<AtomicText type="bodySmall" style={styles.emptyDescription}>{translations.emptyDescription}</AtomicText>
|
|
77
|
+
</View>
|
|
78
|
+
), [translations.emptyTitle, translations.emptyDescription, tokens.colors]);
|
|
79
|
+
|
|
80
|
+
const renderItem = useCallback(({ item }: { item: Reminder }) => (
|
|
81
|
+
<ReminderItem
|
|
82
|
+
reminder={item}
|
|
83
|
+
translations={{
|
|
84
|
+
frequencyOnce: translations.frequencyOnce,
|
|
85
|
+
frequencyDaily: translations.frequencyDaily,
|
|
86
|
+
frequencyWeekly: translations.frequencyWeekly,
|
|
87
|
+
frequencyMonthly: translations.frequencyMonthly,
|
|
88
|
+
}}
|
|
89
|
+
onToggle={handleToggle}
|
|
90
|
+
onEdit={onEditPress}
|
|
91
|
+
onDelete={handleDelete}
|
|
92
|
+
/>
|
|
93
|
+
), [translations, handleToggle, onEditPress, handleDelete]);
|
|
94
|
+
|
|
95
|
+
const keyExtractor = useCallback((item: Reminder) => item.id, []);
|
|
61
96
|
|
|
62
97
|
if (isLoading) {
|
|
63
98
|
return (
|
|
@@ -68,32 +103,20 @@ export const ReminderListScreen: React.FC<ReminderListScreenProps> = ({
|
|
|
68
103
|
}
|
|
69
104
|
|
|
70
105
|
return (
|
|
71
|
-
<ScreenLayout footer={fab}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
translations={{
|
|
86
|
-
frequencyOnce: translations.frequencyOnce,
|
|
87
|
-
frequencyDaily: translations.frequencyDaily,
|
|
88
|
-
frequencyWeekly: translations.frequencyWeekly,
|
|
89
|
-
frequencyMonthly: translations.frequencyMonthly,
|
|
90
|
-
}}
|
|
91
|
-
onToggle={handleToggle}
|
|
92
|
-
onEdit={onEditPress}
|
|
93
|
-
onDelete={handleDelete}
|
|
94
|
-
/>
|
|
95
|
-
))
|
|
96
|
-
)}
|
|
106
|
+
<ScreenLayout footer={fab} scrollable={false}>
|
|
107
|
+
<FlatList
|
|
108
|
+
data={reminders}
|
|
109
|
+
renderItem={renderItem}
|
|
110
|
+
keyExtractor={keyExtractor}
|
|
111
|
+
ListEmptyComponent={renderEmptyState}
|
|
112
|
+
contentContainerStyle={reminders.length === 0 ? styles.listEmptyContent : styles.listContent}
|
|
113
|
+
showsVerticalScrollIndicator={false}
|
|
114
|
+
removeClippedSubviews={true}
|
|
115
|
+
maxToRenderPerBatch={10}
|
|
116
|
+
updateCellsBatchingPeriod={50}
|
|
117
|
+
initialNumToRender={8}
|
|
118
|
+
windowSize={5}
|
|
119
|
+
/>
|
|
97
120
|
</ScreenLayout>
|
|
98
121
|
);
|
|
99
122
|
};
|
|
@@ -101,6 +124,7 @@ export const ReminderListScreen: React.FC<ReminderListScreenProps> = ({
|
|
|
101
124
|
const createStyles = (tokens: ReturnType<typeof useAppDesignTokens>) =>
|
|
102
125
|
StyleSheet.create({
|
|
103
126
|
listContent: { padding: 16, flexGrow: 1 },
|
|
127
|
+
listEmptyContent: { flexGrow: 1 },
|
|
104
128
|
emptyContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 32, paddingTop: 100 },
|
|
105
129
|
emptyIconContainer: {
|
|
106
130
|
width: 80,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common Icon SVG Paths
|
|
3
|
+
*
|
|
4
|
+
* Centralized SVG paths for frequently used icons
|
|
5
|
+
* Works without external icon libraries
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const ICON_PATHS = {
|
|
9
|
+
// Navigation
|
|
10
|
+
'chevron-up': "M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z",
|
|
11
|
+
'chevron-down': "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z",
|
|
12
|
+
'chevron-forward': "M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z",
|
|
13
|
+
'chevron-back': "M15.41 7.41L10.83 12l4.58 4.59L14 18l-6-6 6-6z",
|
|
14
|
+
'arrow-right': "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z",
|
|
15
|
+
'arrow-forward': "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z",
|
|
16
|
+
'arrow-left': "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z",
|
|
17
|
+
|
|
18
|
+
// UI Elements
|
|
19
|
+
'close': "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z",
|
|
20
|
+
'checkmark': "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z",
|
|
21
|
+
'checkmark-circle': "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",
|
|
22
|
+
'plus': "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z",
|
|
23
|
+
'search': "M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z",
|
|
24
|
+
|
|
25
|
+
// Status & Feedback
|
|
26
|
+
'star': "M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z",
|
|
27
|
+
'alert-circle': "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z",
|
|
28
|
+
'information-circle': "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z",
|
|
29
|
+
'warning': "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z",
|
|
30
|
+
|
|
31
|
+
// Communication
|
|
32
|
+
'chatbubble-outline': "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z",
|
|
33
|
+
'mail': "M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z",
|
|
34
|
+
|
|
35
|
+
// Time & Notifications
|
|
36
|
+
'time': "M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z",
|
|
37
|
+
'moon': "M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z",
|
|
38
|
+
|
|
39
|
+
// Users & Social
|
|
40
|
+
'users': "M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z",
|
|
41
|
+
'person': "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z",
|
|
42
|
+
|
|
43
|
+
// Actions
|
|
44
|
+
'create': "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z",
|
|
45
|
+
'trash': "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z",
|
|
46
|
+
'share': "M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z",
|
|
47
|
+
|
|
48
|
+
// Misc
|
|
49
|
+
'globe': "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z",
|
|
50
|
+
'settings': "M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z",
|
|
51
|
+
'heart': "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z",
|
|
52
|
+
'heart-outline': "M16.5 3c-1.74 0-3.41.81-4.5 2.09C10.91 3.81 9.24 3 7.5 3 4.42 3 2 5.42 2 8.5c0 3.78 3.4 6.86 8.55 11.54L12 21.35l1.45-1.32C18.6 15.36 22 12.28 22 8.5 22 5.42 19.58 3 16.5 3zm-4.4 15.55l-.1.1-.1-.1C7.14 14.24 4 11.39 4 8.5 4 6.5 5.5 5 7.5 5c1.54 0 3.04.99 3.57 2.36h1.87C13.46 5.99 14.96 5 16.5 5c2 0 3.5 1.5 3.5 3.5 0 2.89-3.14 5.74-7.9 10.05z",
|
|
53
|
+
|
|
54
|
+
// Notifications
|
|
55
|
+
'notifications': "M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6-6v-5c0-3.07-1.63-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.64 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2zm-2 1H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6z",
|
|
56
|
+
'notifications-off': "M12 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm0-18c.83 0 1.5.67 1.5 1.5 0 .24-.05.46-.14.67l.94.94C14.74 6.57 15 5.82 15 5c0-1.66-1.34-3-3-3-.82 0-1.57.26-2.18.69l.95.95c.2-.09.43-.14.67-.14zM2.81 2.81L1.39 4.22l2.68 2.68C3.06 8.08 2.38 9.5 2.12 11H4.14c.24-1.12.76-2.13 1.48-2.96l1.94 1.94c-.06.34-.1.69-.1 1.02 0 2.48 1.51 4.5 4 4.5.33 0 .68-.04 1.02-.1l4.23 4.23c-.66.32-1.39.51-2.17.51-2.48 0-4.5-2.02-4.5-4.5h-2c0 2.93 1.81 5.45 4.38 6.51l2.5 2.5 1.41-1.41L2.81 2.81z",
|
|
57
|
+
} as const;
|
|
58
|
+
|
|
59
|
+
export type IconPathName = keyof typeof ICON_PATHS;
|