@umituz/react-native-settings 4.17.26 → 4.17.30
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 +15 -6
- package/src/domains/about/presentation/components/AboutSection.tsx +14 -71
- package/src/domains/appearance/application/ports/IAppearanceRepository.ts +8 -0
- package/src/domains/appearance/hooks/index.ts +1 -1
- package/src/domains/appearance/hooks/useAppearance.ts +18 -58
- package/src/domains/appearance/hooks/useAppearanceActions.ts +20 -128
- package/src/domains/appearance/infrastructure/repositories/AppearanceRepository.ts +34 -0
- package/src/domains/appearance/infrastructure/services/AppearanceService.ts +51 -0
- package/src/domains/appearance/presentation/components/AppearanceSection.tsx +2 -2
- package/src/domains/appearance/presentation/hooks/mutations/useAppearanceMutations.ts +36 -0
- package/src/domains/appearance/presentation/hooks/queries/useAppearanceQuery.ts +15 -0
- package/src/domains/disclaimer/presentation/components/DisclaimerModal.tsx +37 -40
- package/src/domains/faqs/presentation/components/FAQSection.tsx +1 -1
- package/src/domains/feedback/presentation/components/FeedbackModal.tsx +11 -15
- package/src/domains/feedback/presentation/components/SupportSection.tsx +2 -2
- package/src/domains/legal/presentation/components/LegalItem.tsx +13 -129
- package/src/index.ts +15 -9
- package/src/infrastructure/repositories/SettingsRepository.ts +105 -0
- package/src/infrastructure/services/SettingsService.ts +47 -0
- package/src/presentation/components/SettingItem.tsx +77 -129
- package/src/presentation/components/SettingsFooter.tsx +9 -25
- package/src/presentation/components/SettingsSection.tsx +9 -20
- package/src/presentation/hooks/mutations/useSettingsMutations.ts +58 -0
- package/src/presentation/hooks/queries/useSettingsQuery.ts +27 -0
- package/src/presentation/hooks/useSettings.ts +45 -0
- package/src/presentation/screens/components/SettingsContent.tsx +20 -247
- package/src/presentation/screens/components/sections/CustomSettingsList.tsx +31 -0
- package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +55 -0
- package/src/presentation/screens/components/sections/IdentitySettingsSection.tsx +43 -0
- package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +47 -0
- package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +84 -0
- package/src/presentation/screens/hooks/useFeatureDetection.ts +1 -16
- package/src/presentation/screens/types/FeatureConfig.ts +18 -0
- package/src/presentation/screens/types/SettingsConfig.ts +7 -0
- package/src/domains/appearance/infrastructure/services/appearanceService.ts +0 -301
- package/src/domains/appearance/infrastructure/storage/appearanceStorage.ts +0 -120
- package/src/domains/appearance/infrastructure/stores/appearanceStore.ts +0 -132
- package/src/infrastructure/storage/SettingsStore.ts +0 -189
- package/src/infrastructure/storage/__tests__/SettingsStore.test.tsx +0 -302
- package/src/presentation/components/CloudSyncSetting.tsx +0 -58
- /package/src/{domain/repositories → application/ports}/ISettingsRepository.ts +0 -0
|
@@ -1,47 +1,31 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Setting Item Component
|
|
3
|
-
* Single Responsibility: Render a single settings item
|
|
4
|
-
* Material Design 3 style with hover effects and modern spacing
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import React from "react";
|
|
8
|
-
import { View,
|
|
9
|
-
import {
|
|
2
|
+
import { View, StyleSheet, Switch } from "react-native";
|
|
3
|
+
import {
|
|
4
|
+
AtomicIcon,
|
|
5
|
+
AtomicText,
|
|
6
|
+
useResponsiveDesignTokens,
|
|
7
|
+
ListItem
|
|
8
|
+
} from "@umituz/react-native-design-system";
|
|
10
9
|
|
|
11
10
|
export interface SettingItemProps {
|
|
12
|
-
/** Icon name (Ionicons) */
|
|
13
11
|
icon: string;
|
|
14
|
-
/** Main title text */
|
|
15
12
|
title: string;
|
|
16
|
-
/** Optional description/value text */
|
|
17
13
|
value?: string;
|
|
18
|
-
/** Callback when pressed */
|
|
19
14
|
onPress?: () => void;
|
|
20
|
-
/** Show switch instead of chevron */
|
|
21
15
|
showSwitch?: boolean;
|
|
22
|
-
/** Switch value */
|
|
23
16
|
switchValue?: boolean;
|
|
24
|
-
/** Switch change handler */
|
|
25
17
|
onSwitchChange?: (value: boolean) => void;
|
|
26
|
-
/** Is last item in section (no divider) */
|
|
27
18
|
isLast?: boolean;
|
|
28
|
-
/** Custom icon color */
|
|
29
19
|
iconColor?: string;
|
|
30
|
-
/** Custom title color */
|
|
31
20
|
titleColor?: string;
|
|
32
|
-
/** Test ID for E2E testing */
|
|
33
21
|
testID?: string;
|
|
34
|
-
/** Disable the item */
|
|
35
22
|
disabled?: boolean;
|
|
36
|
-
/** Custom switch thumb color */
|
|
37
|
-
switchThumbColor?: string;
|
|
38
|
-
/** Custom switch track colors */
|
|
39
|
-
switchTrackColors?: {
|
|
40
|
-
false: string;
|
|
41
|
-
true: string;
|
|
42
|
-
};
|
|
43
23
|
}
|
|
44
24
|
|
|
25
|
+
/**
|
|
26
|
+
* SettingItem - Enhanced ListItem for Settings
|
|
27
|
+
* Uses design system's ListItem molecule with custom switch support
|
|
28
|
+
*/
|
|
45
29
|
export const SettingItem: React.FC<SettingItemProps> = ({
|
|
46
30
|
icon,
|
|
47
31
|
title,
|
|
@@ -55,148 +39,112 @@ export const SettingItem: React.FC<SettingItemProps> = ({
|
|
|
55
39
|
titleColor,
|
|
56
40
|
testID,
|
|
57
41
|
disabled = false,
|
|
58
|
-
switchThumbColor,
|
|
59
|
-
switchTrackColors,
|
|
60
42
|
}) => {
|
|
61
43
|
const tokens = useResponsiveDesignTokens();
|
|
62
|
-
const colors = tokens.colors;
|
|
63
44
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
45
|
+
// For switch items, we need custom rendering
|
|
46
|
+
if (showSwitch) {
|
|
47
|
+
return (
|
|
48
|
+
<View
|
|
49
|
+
style={[
|
|
50
|
+
styles.switchContainer,
|
|
69
51
|
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
52
|
+
borderBottomWidth: isLast ? 0 : 1,
|
|
53
|
+
borderBottomColor: `${tokens.colors.onSurface}10`,
|
|
54
|
+
}
|
|
74
55
|
]}
|
|
75
|
-
onPress={onPress}
|
|
76
|
-
disabled={showSwitch || disabled}
|
|
77
|
-
testID={testID}
|
|
78
56
|
>
|
|
79
|
-
<View style={styles.
|
|
80
|
-
<View
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
backgroundColor: iconColor
|
|
85
|
-
? `${iconColor}15`
|
|
86
|
-
: `${colors.primary}15`,
|
|
87
|
-
},
|
|
88
|
-
]}
|
|
89
|
-
>
|
|
57
|
+
<View style={styles.switchContent}>
|
|
58
|
+
<View style={[
|
|
59
|
+
styles.iconWrapper,
|
|
60
|
+
{ backgroundColor: iconColor ? `${iconColor}15` : `${tokens.colors.primary}15` }
|
|
61
|
+
]}>
|
|
90
62
|
<AtomicIcon
|
|
91
63
|
name={icon}
|
|
92
|
-
|
|
93
|
-
customColor={iconColor || colors.primary}
|
|
64
|
+
size="md"
|
|
65
|
+
customColor={iconColor || tokens.colors.primary}
|
|
94
66
|
/>
|
|
95
67
|
</View>
|
|
96
68
|
<View style={styles.textContainer}>
|
|
97
|
-
<
|
|
69
|
+
<AtomicText
|
|
70
|
+
type="bodyLarge"
|
|
71
|
+
color={disabled ? "surfaceVariant" : "onSurface"}
|
|
98
72
|
style={[
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
color: disabled
|
|
102
|
-
? colors.textSecondary
|
|
103
|
-
: titleColor || colors.textPrimary,
|
|
104
|
-
opacity: disabled ? 0.5 : 1,
|
|
105
|
-
},
|
|
73
|
+
titleColor ? { color: titleColor } : {},
|
|
74
|
+
{ opacity: disabled ? 0.6 : 1 }
|
|
106
75
|
]}
|
|
107
76
|
numberOfLines={1}
|
|
108
77
|
>
|
|
109
78
|
{title}
|
|
110
|
-
</
|
|
111
|
-
{value &&
|
|
112
|
-
<
|
|
113
|
-
|
|
79
|
+
</AtomicText>
|
|
80
|
+
{value && (
|
|
81
|
+
<AtomicText
|
|
82
|
+
type="bodySmall"
|
|
83
|
+
color="secondary"
|
|
114
84
|
numberOfLines={2}
|
|
85
|
+
style={{ marginTop: 2 }}
|
|
115
86
|
>
|
|
116
87
|
{value}
|
|
117
|
-
</
|
|
88
|
+
</AtomicText>
|
|
118
89
|
)}
|
|
119
90
|
</View>
|
|
120
91
|
</View>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
{
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
thumbColor={switchThumbColor || "#FFFFFF"}
|
|
132
|
-
ios_backgroundColor={`${colors.textSecondary}30`}
|
|
133
|
-
/>
|
|
134
|
-
) : (
|
|
135
|
-
<AtomicIcon
|
|
136
|
-
name="chevron-forward-outline"
|
|
137
|
-
customSize={20}
|
|
138
|
-
customColor={colors.textSecondary}
|
|
139
|
-
/>
|
|
140
|
-
)}
|
|
141
|
-
</View>
|
|
142
|
-
</Pressable>
|
|
143
|
-
|
|
144
|
-
{!isLast && (
|
|
145
|
-
<View
|
|
146
|
-
style={[
|
|
147
|
-
styles.divider,
|
|
148
|
-
{ backgroundColor: `${colors.textSecondary}20` },
|
|
149
|
-
]}
|
|
92
|
+
<Switch
|
|
93
|
+
value={switchValue}
|
|
94
|
+
onValueChange={onSwitchChange}
|
|
95
|
+
trackColor={{
|
|
96
|
+
false: tokens.colors.surfaceVariant,
|
|
97
|
+
true: tokens.colors.primary
|
|
98
|
+
}}
|
|
99
|
+
thumbColor="#FFFFFF"
|
|
100
|
+
ios_backgroundColor={tokens.colors.surfaceVariant}
|
|
101
|
+
disabled={disabled}
|
|
150
102
|
/>
|
|
151
|
-
|
|
152
|
-
|
|
103
|
+
</View>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Use design system's ListItem for regular items
|
|
108
|
+
return (
|
|
109
|
+
<ListItem
|
|
110
|
+
title={title}
|
|
111
|
+
subtitle={value}
|
|
112
|
+
leftIcon={icon}
|
|
113
|
+
rightIcon="chevron-forward"
|
|
114
|
+
onPress={onPress}
|
|
115
|
+
disabled={disabled}
|
|
116
|
+
style={{
|
|
117
|
+
borderBottomWidth: isLast ? 0 : 1,
|
|
118
|
+
borderBottomColor: `${tokens.colors.onSurface}10`,
|
|
119
|
+
}}
|
|
120
|
+
/>
|
|
153
121
|
);
|
|
154
122
|
};
|
|
155
123
|
|
|
156
124
|
const styles = StyleSheet.create({
|
|
157
|
-
|
|
125
|
+
switchContainer: {
|
|
158
126
|
flexDirection: "row",
|
|
159
127
|
alignItems: "center",
|
|
160
128
|
justifyContent: "space-between",
|
|
161
129
|
paddingHorizontal: 16,
|
|
162
|
-
paddingVertical:
|
|
163
|
-
minHeight:
|
|
130
|
+
paddingVertical: 12,
|
|
131
|
+
minHeight: 64,
|
|
164
132
|
},
|
|
165
|
-
|
|
133
|
+
switchContent: {
|
|
166
134
|
flexDirection: "row",
|
|
167
135
|
alignItems: "center",
|
|
168
136
|
flex: 1,
|
|
169
137
|
},
|
|
170
|
-
|
|
171
|
-
width:
|
|
172
|
-
height:
|
|
173
|
-
borderRadius:
|
|
138
|
+
iconWrapper: {
|
|
139
|
+
width: 40,
|
|
140
|
+
height: 40,
|
|
141
|
+
borderRadius: 10,
|
|
174
142
|
justifyContent: "center",
|
|
175
143
|
alignItems: "center",
|
|
176
|
-
marginRight:
|
|
144
|
+
marginRight: 12,
|
|
177
145
|
},
|
|
178
146
|
textContainer: {
|
|
179
147
|
flex: 1,
|
|
180
|
-
|
|
181
|
-
},
|
|
182
|
-
title: {
|
|
183
|
-
fontSize: 16,
|
|
184
|
-
fontWeight: "500",
|
|
185
|
-
lineHeight: 20,
|
|
186
|
-
},
|
|
187
|
-
value: {
|
|
188
|
-
fontSize: 14,
|
|
189
|
-
fontWeight: "400",
|
|
190
|
-
marginTop: 4,
|
|
191
|
-
lineHeight: 18,
|
|
192
|
-
},
|
|
193
|
-
rightContainer: {
|
|
194
|
-
flexDirection: "row",
|
|
195
|
-
alignItems: "center",
|
|
196
|
-
gap: 8,
|
|
197
|
-
},
|
|
198
|
-
divider: {
|
|
199
|
-
height: 1,
|
|
200
|
-
marginLeft: 80,
|
|
148
|
+
paddingRight: 8,
|
|
201
149
|
},
|
|
202
150
|
});
|
|
@@ -1,45 +1,32 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Settings Footer Component
|
|
3
|
-
* Single Responsibility: Display app version information
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import React from "react";
|
|
7
|
-
import { View,
|
|
8
|
-
import { useResponsiveDesignTokens } from "@umituz/react-native-design-system";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
import { useResponsiveDesignTokens, AtomicText } from "@umituz/react-native-design-system";
|
|
9
4
|
|
|
10
5
|
export interface SettingsFooterProps {
|
|
11
|
-
/** Custom version text (optional) - should include version number from app config */
|
|
12
6
|
versionText?: string;
|
|
13
|
-
/** App version number from app config (e.g., "1.0.0") */
|
|
14
7
|
appVersion?: string;
|
|
15
|
-
/** Label for version (e.g., "Version") */
|
|
16
8
|
versionLabel?: string;
|
|
17
9
|
}
|
|
18
10
|
|
|
19
11
|
export const SettingsFooter: React.FC<SettingsFooterProps> = ({
|
|
20
12
|
versionText,
|
|
21
13
|
appVersion,
|
|
22
|
-
versionLabel
|
|
14
|
+
versionLabel,
|
|
23
15
|
}) => {
|
|
24
16
|
const tokens = useResponsiveDesignTokens();
|
|
25
17
|
const colors = tokens.colors;
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
// Otherwise build from label + appVersion
|
|
29
|
-
const displayText = versionText || (appVersion
|
|
19
|
+
const displayText = versionText || (appVersion && versionLabel
|
|
30
20
|
? `${versionLabel} ${appVersion}`
|
|
31
|
-
:
|
|
21
|
+
: appVersion || versionText);
|
|
32
22
|
|
|
33
|
-
|
|
34
|
-
if (!displayText) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
23
|
+
if (!displayText) return null;
|
|
37
24
|
|
|
38
25
|
return (
|
|
39
26
|
<View style={styles.container}>
|
|
40
|
-
<
|
|
27
|
+
<AtomicText type="labelSmall" style={{ color: colors.textSecondary }}>
|
|
41
28
|
{displayText}
|
|
42
|
-
</
|
|
29
|
+
</AtomicText>
|
|
43
30
|
</View>
|
|
44
31
|
);
|
|
45
32
|
};
|
|
@@ -49,9 +36,6 @@ const styles = StyleSheet.create({
|
|
|
49
36
|
paddingVertical: 24,
|
|
50
37
|
alignItems: "center",
|
|
51
38
|
},
|
|
52
|
-
text: {
|
|
53
|
-
fontSize: 12,
|
|
54
|
-
fontWeight: "500",
|
|
55
|
-
},
|
|
56
39
|
});
|
|
57
40
|
|
|
41
|
+
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Settings Section Component
|
|
3
|
-
* Single Responsibility: Render a settings section with title and container
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import React from "react";
|
|
7
|
-
import { View,
|
|
8
|
-
import { useResponsiveDesignTokens } from "@umituz/react-native-design-system";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
import { useResponsiveDesignTokens, AtomicText } from "@umituz/react-native-design-system";
|
|
9
4
|
|
|
10
5
|
export interface SettingsSectionProps {
|
|
11
|
-
/** Section title */
|
|
12
6
|
title: string;
|
|
13
|
-
/** Section content */
|
|
14
7
|
children: React.ReactNode;
|
|
15
8
|
}
|
|
16
9
|
|
|
@@ -23,12 +16,12 @@ export const SettingsSection: React.FC<SettingsSectionProps> = ({
|
|
|
23
16
|
|
|
24
17
|
return (
|
|
25
18
|
<View style={[styles.container, { backgroundColor: colors.surface }]}>
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{children}
|
|
19
|
+
<View style={styles.titleContainer}>
|
|
20
|
+
<AtomicText type="titleLarge" color="primary">
|
|
21
|
+
{title}
|
|
22
|
+
</AtomicText>
|
|
31
23
|
</View>
|
|
24
|
+
{children}
|
|
32
25
|
</View>
|
|
33
26
|
);
|
|
34
27
|
};
|
|
@@ -39,15 +32,11 @@ const styles = StyleSheet.create({
|
|
|
39
32
|
borderRadius: 12,
|
|
40
33
|
overflow: "hidden",
|
|
41
34
|
},
|
|
42
|
-
|
|
43
|
-
fontSize: 18,
|
|
44
|
-
fontWeight: "600",
|
|
35
|
+
titleContainer: {
|
|
45
36
|
paddingHorizontal: 16,
|
|
46
37
|
paddingTop: 16,
|
|
47
38
|
paddingBottom: 8,
|
|
48
39
|
},
|
|
49
|
-
content: {
|
|
50
|
-
borderRadius: 0,
|
|
51
|
-
},
|
|
52
40
|
});
|
|
53
41
|
|
|
42
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSettingsMutations Hook
|
|
3
|
+
*
|
|
4
|
+
* Mutations for updating and resetting user settings
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
8
|
+
import { getSettingsService } from '../../../infrastructure/services/SettingsService';
|
|
9
|
+
import { SETTINGS_QUERY_KEY } from '../queries/useSettingsQuery';
|
|
10
|
+
import type { UserSettings } from '../../../application/ports/ISettingsRepository';
|
|
11
|
+
|
|
12
|
+
export const useUpdateSettingsMutation = (userId: string) => {
|
|
13
|
+
const queryClient = useQueryClient();
|
|
14
|
+
const settingsService = getSettingsService();
|
|
15
|
+
|
|
16
|
+
return useMutation({
|
|
17
|
+
mutationFn: async (updates: Partial<UserSettings>) => {
|
|
18
|
+
const currentResult = await settingsService.getSettings(userId);
|
|
19
|
+
if (!currentResult.success || !currentResult.data) {
|
|
20
|
+
throw new Error('Could not find existing settings to update');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const updatedSettings = {
|
|
24
|
+
...currentResult.data,
|
|
25
|
+
...updates,
|
|
26
|
+
updatedAt: new Date(),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const result = await settingsService.saveSettings(updatedSettings);
|
|
30
|
+
if (!result.success) {
|
|
31
|
+
throw new Error(result.error?.message || 'Failed to update settings');
|
|
32
|
+
}
|
|
33
|
+
return updatedSettings;
|
|
34
|
+
},
|
|
35
|
+
onSuccess: (data) => {
|
|
36
|
+
queryClient.setQueryData([...SETTINGS_QUERY_KEY, userId], data);
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const useResetSettingsMutation = (userId: string) => {
|
|
42
|
+
const queryClient = useQueryClient();
|
|
43
|
+
const settingsService = getSettingsService();
|
|
44
|
+
|
|
45
|
+
return useMutation({
|
|
46
|
+
mutationFn: async () => {
|
|
47
|
+
const result = await settingsService.resetSettings(userId);
|
|
48
|
+
// resetSettings returns the defaults as data
|
|
49
|
+
if (!result.success) {
|
|
50
|
+
throw new Error(result.error?.message || 'Failed to reset settings');
|
|
51
|
+
}
|
|
52
|
+
return (result as any).data as UserSettings;
|
|
53
|
+
},
|
|
54
|
+
onSuccess: (data) => {
|
|
55
|
+
queryClient.setQueryData([...SETTINGS_QUERY_KEY, userId], data);
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSettingsQuery Hook
|
|
3
|
+
*
|
|
4
|
+
* Fetches user settings using TanStack Query
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useQuery } from '@tanstack/react-query';
|
|
8
|
+
import { getSettingsService } from '../../../infrastructure/services/SettingsService';
|
|
9
|
+
import type { UserSettings } from '../../../application/ports/ISettingsRepository';
|
|
10
|
+
|
|
11
|
+
export const SETTINGS_QUERY_KEY = ['settings'];
|
|
12
|
+
|
|
13
|
+
export const useSettingsQuery = (userId: string) => {
|
|
14
|
+
const settingsService = getSettingsService();
|
|
15
|
+
|
|
16
|
+
return useQuery({
|
|
17
|
+
queryKey: [...SETTINGS_QUERY_KEY, userId],
|
|
18
|
+
queryFn: async () => {
|
|
19
|
+
const result = await settingsService.getSettings(userId);
|
|
20
|
+
if (!result.success || !result.data) {
|
|
21
|
+
throw new Error(result.error?.message || 'Failed to load settings');
|
|
22
|
+
}
|
|
23
|
+
return result.data;
|
|
24
|
+
},
|
|
25
|
+
enabled: !!userId,
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSettings Hook
|
|
3
|
+
*
|
|
4
|
+
* Primary hook for accessing and managing user settings.
|
|
5
|
+
* Integrates with TanStack Query mutations and queries.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useSettingsQuery } from './queries/useSettingsQuery';
|
|
9
|
+
import { useUpdateSettingsMutation, useResetSettingsMutation } from './mutations/useSettingsMutations';
|
|
10
|
+
import type { UserSettings } from '../../application/ports/ISettingsRepository';
|
|
11
|
+
|
|
12
|
+
export const useSettings = (userId: string) => {
|
|
13
|
+
const {
|
|
14
|
+
data: settings,
|
|
15
|
+
isLoading: loading,
|
|
16
|
+
error: queryError
|
|
17
|
+
} = useSettingsQuery(userId);
|
|
18
|
+
|
|
19
|
+
const updateMutation = useUpdateSettingsMutation(userId);
|
|
20
|
+
const resetMutation = useResetSettingsMutation(userId);
|
|
21
|
+
|
|
22
|
+
const updateSettings = async (updates: Partial<UserSettings>) => {
|
|
23
|
+
return updateMutation.mutateAsync(updates);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const resetSettings = async () => {
|
|
27
|
+
return resetMutation.mutateAsync();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const error = queryError instanceof Error
|
|
31
|
+
? queryError.message
|
|
32
|
+
: updateMutation.error instanceof Error
|
|
33
|
+
? updateMutation.error.message
|
|
34
|
+
: resetMutation.error instanceof Error
|
|
35
|
+
? resetMutation.error.message
|
|
36
|
+
: null;
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
settings,
|
|
40
|
+
loading: loading || updateMutation.isPending || resetMutation.isPending,
|
|
41
|
+
error,
|
|
42
|
+
updateSettings,
|
|
43
|
+
resetSettings,
|
|
44
|
+
};
|
|
45
|
+
};
|