@umituz/react-native-settings 4.17.27 → 4.17.31

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.
Files changed (44) hide show
  1. package/package.json +15 -4
  2. package/src/domains/about/presentation/components/AboutSection.tsx +14 -71
  3. package/src/domains/appearance/application/ports/IAppearanceRepository.ts +8 -0
  4. package/src/domains/appearance/hooks/index.ts +1 -1
  5. package/src/domains/appearance/hooks/useAppearance.ts +18 -58
  6. package/src/domains/appearance/hooks/useAppearanceActions.ts +20 -128
  7. package/src/domains/appearance/infrastructure/repositories/AppearanceRepository.ts +34 -0
  8. package/src/domains/appearance/infrastructure/services/AppearanceService.ts +51 -0
  9. package/src/domains/appearance/presentation/components/AppearanceSection.tsx +2 -2
  10. package/src/domains/appearance/presentation/hooks/mutations/useAppearanceMutations.ts +36 -0
  11. package/src/domains/appearance/presentation/hooks/queries/useAppearanceQuery.ts +15 -0
  12. package/src/domains/disclaimer/presentation/components/DisclaimerModal.tsx +37 -40
  13. package/src/domains/faqs/presentation/components/FAQSection.tsx +1 -1
  14. package/src/domains/faqs/presentation/screens/FAQScreen.tsx +1 -1
  15. package/src/domains/feedback/presentation/components/FeedbackModal.tsx +11 -15
  16. package/src/domains/feedback/presentation/components/SupportSection.tsx +2 -2
  17. package/src/domains/legal/presentation/components/LegalItem.tsx +13 -129
  18. package/src/index.ts +19 -9
  19. package/src/infrastructure/repositories/SettingsRepository.ts +105 -0
  20. package/src/infrastructure/services/SettingsService.ts +47 -0
  21. package/src/presentation/components/SettingItem.tsx +77 -129
  22. package/src/presentation/components/SettingsFooter.tsx +9 -25
  23. package/src/presentation/components/SettingsSection.tsx +9 -20
  24. package/src/presentation/hooks/mutations/useSettingsMutations.ts +58 -0
  25. package/src/presentation/hooks/queries/useSettingsQuery.ts +27 -0
  26. package/src/presentation/hooks/useSettings.ts +45 -0
  27. package/src/presentation/screens/components/SettingsContent.tsx +20 -247
  28. package/src/presentation/screens/components/sections/CustomSettingsList.tsx +31 -0
  29. package/src/presentation/screens/components/sections/FeatureSettingsSection.tsx +68 -0
  30. package/src/presentation/screens/components/sections/IdentitySettingsSection.tsx +43 -0
  31. package/src/presentation/screens/components/sections/ProfileSectionLoader.tsx +47 -0
  32. package/src/presentation/screens/components/sections/SubscriptionSettingsItem.tsx +157 -0
  33. package/src/presentation/screens/components/sections/SupportSettingsSection.tsx +84 -0
  34. package/src/presentation/screens/hooks/useFeatureDetection.ts +1 -16
  35. package/src/presentation/screens/types/FeatureConfig.ts +35 -10
  36. package/src/presentation/screens/types/SettingsConfig.ts +7 -0
  37. package/src/presentation/screens/types/index.ts +1 -0
  38. package/src/domains/appearance/infrastructure/services/appearanceService.ts +0 -301
  39. package/src/domains/appearance/infrastructure/storage/appearanceStorage.ts +0 -120
  40. package/src/domains/appearance/infrastructure/stores/appearanceStore.ts +0 -132
  41. package/src/infrastructure/storage/SettingsStore.ts +0 -189
  42. package/src/infrastructure/storage/__tests__/SettingsStore.test.tsx +0 -302
  43. package/src/presentation/components/CloudSyncSetting.tsx +0 -58
  44. /package/src/{domain/repositories → application/ports}/ISettingsRepository.ts +0 -0
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "4.17.27",
3
+ "version": "4.17.31",
4
4
  "description": "Complete settings hub for React Native apps - consolidated package with settings, about, legal, appearance, feedback, FAQs, and rating",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "scripts": {
8
- "typecheck": "echo 'TypeScript validation passed'",
9
- "lint": "echo 'Lint passed'",
8
+ "typecheck": "tsc --noEmit",
9
+ "lint": "eslint src --ext .ts,.tsx --max-warnings 0",
10
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
10
11
  "version:patch": "npm version patch -m 'chore: release v%s'",
11
12
  "version:minor": "npm version minor -m 'chore: release v%s'",
12
13
  "version:major": "npm version major -m 'chore: release v%s'"
@@ -37,6 +38,7 @@
37
38
  "@expo/vector-icons": ">=14.0.0",
38
39
  "@react-navigation/native": ">=6.0.0",
39
40
  "@react-navigation/stack": ">=6.0.0",
41
+ "@tanstack/react-query": ">=5.0.0",
40
42
  "@umituz/react-native-auth": "latest",
41
43
  "@umituz/react-native-design-system": "latest",
42
44
  "@umituz/react-native-localization": "latest",
@@ -44,6 +46,7 @@
44
46
  "@umituz/react-native-onboarding": "latest",
45
47
  "@umituz/react-native-sentry": "latest",
46
48
  "@umituz/react-native-storage": "latest",
49
+ "@umituz/react-native-tanstack": "latest",
47
50
  "react": ">=19.0.0",
48
51
  "react-native": ">=0.81.0",
49
52
  "react-native-safe-area-context": ">=4.0.0",
@@ -54,14 +57,19 @@
54
57
  "@expo/vector-icons": "^15.0.0",
55
58
  "@react-navigation/native": "^6.1.18",
56
59
  "@react-navigation/stack": "^6.4.1",
60
+ "@tanstack/react-query": "^5.0.0",
57
61
  "@types/jest": "^29.5.14",
58
62
  "@types/react": "~19.1.10",
63
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
64
+ "@typescript-eslint/parser": "^7.0.0",
59
65
  "@umituz/react-native-auth": "latest",
60
66
  "@umituz/react-native-design-system": "latest",
61
67
  "@umituz/react-native-localization": "latest",
62
68
  "@umituz/react-native-notifications": "latest",
63
69
  "@umituz/react-native-onboarding": "latest",
64
70
  "@umituz/react-native-storage": "latest",
71
+ "@umituz/react-native-tanstack": "latest",
72
+ "eslint": "^8.57.0",
65
73
  "react": "19.1.0",
66
74
  "react-native": "0.81.5",
67
75
  "typescript": "^5.3.0"
@@ -75,6 +83,9 @@
75
83
  "LICENSE"
76
84
  ],
77
85
  "dependencies": {
78
- "@umituz/react-native-design-system": "latest"
86
+ "@react-native-async-storage/async-storage": "^2.2.0",
87
+ "@react-native-firebase/app": "^23.7.0",
88
+ "@react-native-firebase/firestore": "^23.7.0",
89
+ "firebase": "^12.7.0"
79
90
  }
80
91
  }
@@ -1,7 +1,11 @@
1
1
  import React from 'react';
2
- import { View, Pressable, StyleSheet, ViewStyle } from 'react-native';
2
+ import { View, StyleSheet, ViewStyle } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
- import { useResponsiveDesignTokens, AtomicIcon, AtomicText } from '@umituz/react-native-design-system';
4
+ import {
5
+ useResponsiveDesignTokens,
6
+ AtomicText,
7
+ ListItem
8
+ } from '@umituz/react-native-design-system';
5
9
  import { AboutConfig } from '../../domain/entities/AppInfo';
6
10
 
7
11
  export interface AboutSectionProps {
@@ -23,7 +27,6 @@ export const AboutSection: React.FC<AboutSectionProps> = ({
23
27
  }) => {
24
28
  const navigation = useNavigation();
25
29
  const tokens = useResponsiveDesignTokens();
26
- const colors = tokens.colors;
27
30
 
28
31
  const route = config?.route || config?.defaultRoute || 'About';
29
32
  const title = propsTitle || config?.title;
@@ -41,57 +44,21 @@ export const AboutSection: React.FC<AboutSectionProps> = ({
41
44
  if (!title) return null;
42
45
 
43
46
  return (
44
- <View style={[styles.sectionContainer, { backgroundColor: colors.surface }, containerStyle]}>
47
+ <View style={[styles.sectionContainer, { backgroundColor: tokens.colors.surface }, containerStyle]}>
45
48
  {!!sectionTitle && (
46
49
  <View style={styles.headerContainer}>
47
- <AtomicText
48
- type="titleMedium"
49
- color="primary"
50
- >
50
+ <AtomicText type="titleMedium" color="primary">
51
51
  {sectionTitle}
52
52
  </AtomicText>
53
53
  </View>
54
54
  )}
55
- <Pressable
56
- style={({ pressed }) => [
57
- styles.itemContainer,
58
- {
59
- backgroundColor: pressed ? `${colors.primary}08` : 'transparent',
60
- },
61
- ]}
55
+ <ListItem
56
+ title={title}
57
+ subtitle={description}
58
+ leftIcon="information-circle"
59
+ rightIcon="chevron-forward"
62
60
  onPress={handlePress}
63
- >
64
- <View style={styles.content}>
65
- <View
66
- style={[
67
- styles.iconContainer,
68
- { backgroundColor: `${colors.primary}15` },
69
- ]}
70
- >
71
- <AtomicIcon name="information-circle" size="lg" color="primary" />
72
- </View>
73
- <View style={styles.textContainer}>
74
- <AtomicText
75
- type="bodyLarge"
76
- color="primary"
77
- numberOfLines={1}
78
- style={{ marginBottom: 4 }}
79
- >
80
- {title}
81
- </AtomicText>
82
- {!!description && (
83
- <AtomicText
84
- type="bodyMedium"
85
- color="secondary"
86
- numberOfLines={2}
87
- >
88
- {description}
89
- </AtomicText>
90
- )}
91
- </View>
92
- <AtomicIcon name="chevron-forward" size="md" color="secondary" />
93
- </View>
94
- </Pressable>
61
+ />
95
62
  </View>
96
63
  );
97
64
  };
@@ -107,28 +74,4 @@ const styles = StyleSheet.create({
107
74
  paddingTop: 16,
108
75
  paddingBottom: 8,
109
76
  },
110
- itemContainer: {
111
- flexDirection: 'row',
112
- alignItems: 'center',
113
- paddingHorizontal: 16,
114
- paddingVertical: 16,
115
- minHeight: 72,
116
- },
117
- content: {
118
- flex: 1,
119
- flexDirection: 'row',
120
- alignItems: 'center',
121
- },
122
- iconContainer: {
123
- width: 48,
124
- height: 48,
125
- borderRadius: 12,
126
- justifyContent: 'center',
127
- alignItems: 'center',
128
- marginRight: 16,
129
- },
130
- textContainer: {
131
- flex: 1,
132
- marginRight: 8,
133
- },
134
77
  });
@@ -0,0 +1,8 @@
1
+ import { ThemeMode, CustomThemeColors } from "@umituz/react-native-design-system";
2
+ import { AppearanceSettings } from "../../types";
3
+
4
+ export interface IAppearanceRepository {
5
+ getSettings(): Promise<AppearanceSettings>;
6
+ saveSettings(settings: AppearanceSettings): Promise<void>;
7
+ clearSettings(): Promise<void>;
8
+ }
@@ -3,4 +3,4 @@
3
3
  */
4
4
 
5
5
  export { useAppearance } from "./useAppearance";
6
- export { useAppearanceActions, type AppearanceActionsConfig } from "./useAppearanceActions";
6
+ export { useAppearanceActions } from "./useAppearanceActions";
@@ -1,61 +1,21 @@
1
- /**
2
- * useAppearance Hook
3
- *
4
- * Hook for accessing appearance state and actions
5
- * Single Responsibility: Presentation layer data access
6
- */
7
-
8
- import { useCallback } from "react";
9
- import { useAppearanceStore } from "../infrastructure/stores/appearanceStore";
10
- import { appearanceService } from "../infrastructure/services/appearanceService";
11
- import type { ThemeMode, CustomThemeColors } from "../types";
1
+ import { useAppearanceQuery } from "../presentation/hooks/queries/useAppearanceQuery";
2
+ import { useAppearanceMutations } from "../presentation/hooks/mutations/useAppearanceMutations";
3
+ import { ThemeMode, CustomThemeColors } from "@umituz/react-native-design-system";
12
4
 
13
5
  export const useAppearance = () => {
14
- const store = useAppearanceStore();
15
-
16
- const setThemeMode = useCallback(
17
- async (mode: ThemeMode) => {
18
- await appearanceService.setThemeMode(mode);
19
- },
20
- []
21
- );
22
-
23
- const toggleTheme = useCallback(
24
- async () => {
25
- await appearanceService.toggleTheme();
26
- },
27
- []
28
- );
29
-
30
- const setCustomColors = useCallback(
31
- async (colors: CustomThemeColors) => {
32
- await appearanceService.setCustomColors(colors);
33
- },
34
- []
35
- );
36
-
37
- const resetCustomColors = useCallback(
38
- async () => {
39
- await appearanceService.resetCustomColors();
40
- },
41
- []
42
- );
43
-
44
- const reset = useCallback(
45
- async () => {
46
- await appearanceService.reset();
47
- },
48
- []
49
- );
50
-
51
- return {
52
- themeMode: store.settings.themeMode,
53
- customColors: store.settings.customColors,
54
- isInitialized: store.isInitialized,
55
- setThemeMode,
56
- toggleTheme,
57
- setCustomColors,
58
- resetCustomColors,
59
- reset,
60
- };
6
+ const { data: settings, isLoading } = useAppearanceQuery();
7
+ const {
8
+ updateThemeMutation,
9
+ updateColorsMutation,
10
+ resetAppearanceMutation
11
+ } = useAppearanceMutations();
12
+
13
+ return {
14
+ themeMode: settings?.themeMode || "dark",
15
+ customColors: settings?.customColors,
16
+ isLoading,
17
+ setThemeMode: (mode: ThemeMode) => updateThemeMutation.mutate(mode),
18
+ setCustomColors: (colors: CustomThemeColors) => updateColorsMutation.mutate(colors),
19
+ reset: () => resetAppearanceMutation.mutate(),
20
+ };
61
21
  };
@@ -1,139 +1,31 @@
1
- /**
2
- * Appearance Actions Hook
3
- * Single Responsibility: Handle appearance-related presentation actions
4
- * Business logic extracted to service layer
5
- */
6
-
7
- import { useCallback, useState, useEffect, useRef } from "react";
1
+ import { useState, useCallback, useEffect } from "react";
8
2
  import { useAppearance } from "./useAppearance";
9
- import type {
10
- ThemeMode,
11
- CustomThemeColors,
12
- } from "@umituz/react-native-design-system";
13
-
14
- export interface UseAppearanceActionsReturn {
15
- localCustomColors: CustomThemeColors;
16
- handleThemeSelect: (mode: ThemeMode) => Promise<void>;
17
- handleColorChange: (key: keyof CustomThemeColors, color: string) => void;
18
- handleResetColors: (onConfirm?: () => void) => void;
19
- }
20
-
21
- export interface AppearanceActionsConfig {
22
- onResetConfirm?: () => void;
23
- onResetCancel?: () => void;
24
- resetTitle?: string;
25
- resetMessage?: string;
26
- confirmLabel?: string;
27
- cancelLabel?: string;
28
- }
3
+ import { CustomThemeColors } from "@umituz/react-native-design-system";
29
4
 
30
- export function useAppearanceActions(
31
- config?: AppearanceActionsConfig
32
- ): UseAppearanceActionsReturn {
33
- const { customColors, setThemeMode, setCustomColors, resetCustomColors } =
34
- useAppearance();
5
+ export const useAppearanceActions = () => {
6
+ const { themeMode, customColors, setThemeMode, setCustomColors, reset } = useAppearance();
7
+ const [localCustomColors, setLocalCustomColors] = useState<CustomThemeColors>(customColors || {});
35
8
 
36
- // Use ref to prevent unnecessary re-renders and memory leaks
37
- const configRef = useRef(config);
38
- configRef.current = config;
39
-
40
- // Initialize local state with custom colors, prevent unnecessary updates
41
- const [localCustomColors, setLocalCustomColors] = useState<CustomThemeColors>(() =>
42
- customColors || {}
43
- );
44
-
45
- // Sync local state with store changes, but only if different
46
9
  useEffect(() => {
47
- if (customColors && JSON.stringify(customColors) !== JSON.stringify(localCustomColors)) {
48
- if (__DEV__) {
49
- console.log("[useAppearanceActions] Syncing local colors with store");
50
- }
10
+ if (customColors) {
51
11
  setLocalCustomColors(customColors);
52
12
  }
53
- }, [customColors]); // Only depend on customColors, not localCustomColors
54
-
55
- const handleThemeSelect = useCallback(
56
- async (mode: ThemeMode) => {
57
- try {
58
- await setThemeMode(mode);
59
- } catch (error) {
60
- if (__DEV__) {
61
- console.error("[useAppearanceActions] Failed to set theme mode:", error);
62
- }
63
- }
64
- },
65
- [setThemeMode],
66
- );
13
+ }, [customColors]);
67
14
 
68
- const handleColorChange = useCallback(
69
- (key: keyof CustomThemeColors, color: string) => {
70
- try {
71
- // Prevent unnecessary updates if color hasn't changed
72
- if (localCustomColors[key] === color) {
73
- return;
74
- }
15
+ const handleThemeSelect = useCallback((mode: any) => {
16
+ setThemeMode(mode);
17
+ }, [setThemeMode]);
75
18
 
76
- const newColors = {
77
- ...localCustomColors,
78
- [key]: color,
79
- };
19
+ const handleColorChange = useCallback((key: keyof CustomThemeColors, color: string) => {
20
+ const newColors = { ...localCustomColors, [key]: color };
21
+ setLocalCustomColors(newColors);
22
+ setCustomColors(newColors);
23
+ }, [localCustomColors, setCustomColors]);
80
24
 
81
- if (__DEV__) {
82
- console.log("[useAppearanceActions] Updating color:", key, color);
83
- }
84
-
85
- setLocalCustomColors(newColors);
86
- setCustomColors(newColors);
87
- } catch (error) {
88
- if (__DEV__) {
89
- console.error("[useAppearanceActions] Failed to update color:", error);
90
- }
91
- }
92
- },
93
- [localCustomColors, setCustomColors],
94
- );
95
-
96
- const handleResetColors = useCallback(
97
- (onConfirm?: () => void) => {
98
- try {
99
- // Generic reset handler - the host app should handle the UI confirmation
100
- const resetAction = async () => {
101
- try {
102
- setLocalCustomColors({});
103
- await resetCustomColors();
104
- onConfirm?.();
105
- configRef.current?.onResetConfirm?.();
106
- } catch (error) {
107
- if (__DEV__) {
108
- console.error("[useAppearanceActions] Failed to reset colors:", error);
109
- }
110
- }
111
- };
112
-
113
- // If no custom config provided, just reset directly
114
- if (!configRef.current?.resetTitle) {
115
- resetAction();
116
- }
117
- // Otherwise, the host app should handle showing the confirmation dialog
118
- // and call resetAction when confirmed
119
- } catch (error) {
120
- if (__DEV__) {
121
- console.error("[useAppearanceActions] Failed to handle reset colors:", error);
122
- }
123
- }
124
- },
125
- [resetCustomColors],
126
- );
127
-
128
- // Cleanup effect
129
- useEffect(() => {
130
- return () => {
131
- // Cleanup any pending operations or references
132
- if (__DEV__) {
133
- console.log("[useAppearanceActions] Cleanup");
134
- }
135
- };
136
- }, []);
25
+ const handleResetColors = useCallback(() => {
26
+ reset();
27
+ setLocalCustomColors({});
28
+ }, [reset]);
137
29
 
138
30
  return {
139
31
  localCustomColors,
@@ -141,4 +33,4 @@ export function useAppearanceActions(
141
33
  handleColorChange,
142
34
  handleResetColors,
143
35
  };
144
- }
36
+ };
@@ -0,0 +1,34 @@
1
+ import { storageRepository, unwrap } from "@umituz/react-native-storage";
2
+ import { IAppearanceRepository } from "../../application/ports/IAppearanceRepository";
3
+ import { AppearanceSettings } from "../../types";
4
+
5
+ const STORAGE_KEY = "@appearance_settings";
6
+ const DEFAULT_SETTINGS: AppearanceSettings = {
7
+ themeMode: "dark",
8
+ };
9
+
10
+ export class AppearanceRepository implements IAppearanceRepository {
11
+ async getSettings(): Promise<AppearanceSettings> {
12
+ const result = await storageRepository.getItem<AppearanceSettings>(
13
+ STORAGE_KEY,
14
+ DEFAULT_SETTINGS
15
+ );
16
+ return unwrap(result, DEFAULT_SETTINGS);
17
+ }
18
+
19
+ async saveSettings(settings: AppearanceSettings): Promise<void> {
20
+ const result = await storageRepository.setItem(STORAGE_KEY, settings);
21
+ if (!result.success) {
22
+ throw new Error("Failed to save appearance settings");
23
+ }
24
+ }
25
+
26
+ async clearSettings(): Promise<void> {
27
+ const result = await storageRepository.removeItem(STORAGE_KEY);
28
+ if (!result.success) {
29
+ throw new Error("Failed to clear appearance settings");
30
+ }
31
+ }
32
+ }
33
+
34
+ export const getAppearanceRepository = () => new AppearanceRepository();
@@ -0,0 +1,51 @@
1
+ import {
2
+ useTheme,
3
+ useDesignSystemTheme,
4
+ ThemeMode,
5
+ CustomThemeColors
6
+ } from "@umituz/react-native-design-system";
7
+ import { IAppearanceRepository } from "../../application/ports/IAppearanceRepository";
8
+ import { getAppearanceRepository } from "../repositories/AppearanceRepository";
9
+ import { AppearanceSettings } from "../../types";
10
+
11
+ export class AppearanceService {
12
+ constructor(private readonly repository: IAppearanceRepository = getAppearanceRepository()) { }
13
+
14
+ async getSettings(): Promise<AppearanceSettings> {
15
+ return this.repository.getSettings();
16
+ }
17
+
18
+ async setThemeMode(mode: ThemeMode): Promise<void> {
19
+ const settings = await this.repository.getSettings();
20
+ const newSettings = { ...settings, themeMode: mode };
21
+ await this.repository.saveSettings(newSettings);
22
+ this.syncWithDesignSystem(newSettings);
23
+ }
24
+
25
+ async setCustomColors(colors: CustomThemeColors): Promise<void> {
26
+ const settings = await this.repository.getSettings();
27
+ const newSettings = {
28
+ ...settings,
29
+ customColors: { ...settings.customColors, ...colors }
30
+ };
31
+ await this.repository.saveSettings(newSettings);
32
+ this.syncWithDesignSystem(newSettings);
33
+ }
34
+
35
+ async resetSettings(): Promise<void> {
36
+ await this.repository.clearSettings();
37
+ const defaultSettings = await this.repository.getSettings();
38
+ this.syncWithDesignSystem(defaultSettings);
39
+ }
40
+
41
+ private syncWithDesignSystem(settings: AppearanceSettings): void {
42
+ useTheme.getState().setThemeMode(settings.themeMode);
43
+ useDesignSystemTheme.getState().setThemeMode(settings.themeMode);
44
+ if (settings.customColors) {
45
+ useDesignSystemTheme.getState().setCustomColors(settings.customColors);
46
+ }
47
+ }
48
+ }
49
+
50
+ export const getAppearanceService = () => new AppearanceService();
51
+ export const appearanceService = getAppearanceService();
@@ -73,7 +73,7 @@ export const AppearanceSection: React.FC<AppearanceSectionProps> = ({
73
73
  { backgroundColor: `${colors.primary}15` },
74
74
  ]}
75
75
  >
76
- <AtomicIcon name="water-outline" size="lg" color="primary" />
76
+ <AtomicIcon name="color-palette" size="lg" color="primary" />
77
77
  </View>
78
78
  <View style={styles.textContainer}>
79
79
  <AtomicText
@@ -94,7 +94,7 @@ export const AppearanceSection: React.FC<AppearanceSectionProps> = ({
94
94
  </AtomicText>
95
95
  )}
96
96
  </View>
97
- <AtomicIcon name="chevron-forward-outline" size="md" color="secondary" />
97
+ <AtomicIcon name="chevron-forward" size="md" color="secondary" />
98
98
  </View>
99
99
  </Pressable>
100
100
  </View>
@@ -0,0 +1,36 @@
1
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
2
+ import { getAppearanceService } from "../../../infrastructure/services/AppearanceService";
3
+ import { appearanceKeys } from "../queries/useAppearanceQuery";
4
+ import { ThemeMode, CustomThemeColors } from "@umituz/react-native-design-system";
5
+
6
+ export const useAppearanceMutations = () => {
7
+ const queryClient = useQueryClient();
8
+ const service = getAppearanceService();
9
+
10
+ const updateThemeMutation = useMutation({
11
+ mutationFn: (mode: ThemeMode) => service.setThemeMode(mode),
12
+ onSuccess: () => {
13
+ queryClient.invalidateQueries({ queryKey: appearanceKeys.settings() });
14
+ },
15
+ });
16
+
17
+ const updateColorsMutation = useMutation({
18
+ mutationFn: (colors: CustomThemeColors) => service.setCustomColors(colors),
19
+ onSuccess: () => {
20
+ queryClient.invalidateQueries({ queryKey: appearanceKeys.settings() });
21
+ },
22
+ });
23
+
24
+ const resetAppearanceMutation = useMutation({
25
+ mutationFn: () => service.resetSettings(),
26
+ onSuccess: () => {
27
+ queryClient.invalidateQueries({ queryKey: appearanceKeys.settings() });
28
+ },
29
+ });
30
+
31
+ return {
32
+ updateThemeMutation,
33
+ updateColorsMutation,
34
+ resetAppearanceMutation,
35
+ };
36
+ };
@@ -0,0 +1,15 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { getAppearanceService } from "../../../infrastructure/services/AppearanceService";
3
+
4
+ export const appearanceKeys = {
5
+ all: ["appearance"] as const,
6
+ settings: () => [...appearanceKeys.all, "settings"] as const,
7
+ };
8
+
9
+ export const useAppearanceQuery = () => {
10
+ const service = getAppearanceService();
11
+ return useQuery({
12
+ queryKey: appearanceKeys.settings(),
13
+ queryFn: () => service.getSettings(),
14
+ });
15
+ };