@umituz/react-native-settings 4.23.45 → 4.23.47

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,11 +1,11 @@
1
1
  {
2
2
  "name": "@umituz/react-native-settings",
3
- "version": "4.23.45",
3
+ "version": "4.23.47",
4
4
  "description": "Complete settings hub for React Native apps - consolidated package with settings, localization, about, legal, appearance, feedback, FAQs, rating, and gamification",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "scripts": {
8
- "typecheck": "tsc --noEmit",
8
+ "typecheck": "tsc --noEmit --skipLibCheck",
9
9
  "lint": "eslint src",
10
10
  "lint:fix": "eslint src --fix",
11
11
  "vp": "npm version patch && npm publish && git push"
@@ -42,13 +42,13 @@
42
42
  "firebase": "^12.7.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@umituz/react-native-design-system": ">=4.23.45",
46
45
  "@expo/vector-icons": ">=14.0.0",
47
46
  "@react-native-async-storage/async-storage": ">=2.0.0",
48
47
  "@react-native-community/datetimepicker": ">=8.0.0",
49
48
  "@react-navigation/native": ">=6.0.0",
50
49
  "@react-navigation/stack": ">=6.0.0",
51
50
  "@tanstack/react-query": ">=5.0.0",
51
+ "@umituz/react-native-design-system": ">=4.23.47",
52
52
  "expo-device": ">=6.0.0",
53
53
  "expo-haptics": ">=15.0.0",
54
54
  "expo-localization": ">=16.0.0",
@@ -62,7 +62,6 @@
62
62
  "zustand": ">=4.0.0"
63
63
  },
64
64
  "devDependencies": {
65
- "@umituz/react-native-design-system": "^4.23.45",
66
65
  "@expo/vector-icons": "^15.0.0",
67
66
  "@gorhom/bottom-sheet": "^5.2.8",
68
67
  "@react-native-async-storage/async-storage": "^2.2.0",
@@ -78,6 +77,7 @@
78
77
  "@typescript-eslint/eslint-plugin": "^7.18.0",
79
78
  "@typescript-eslint/parser": "^7.18.0",
80
79
  "@umituz/react-native-auth": "^3.6.49",
80
+ "@umituz/react-native-design-system": "^4.23.47",
81
81
  "@umituz/react-native-firebase": "^1.13.102",
82
82
  "@umituz/react-native-sentry": "*",
83
83
  "eslint": "^8.57.0",
@@ -1,21 +1,21 @@
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";
1
+ import { useTheme, type ThemeMode, type CustomThemeColors } from "@umituz/react-native-design-system";
4
2
 
5
3
  export const useAppearance = () => {
6
- const { data: settings, isLoading } = useAppearanceQuery();
7
- const {
8
- updateThemeMutation,
9
- updateColorsMutation,
10
- resetAppearanceMutation
11
- } = useAppearanceMutations();
4
+ const { themeMode, customColors, isInitialized, setThemeMode, setCustomColors } = useTheme();
12
5
 
13
- return {
14
- themeMode: settings?.themeMode || "light",
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
- };
6
+ return {
7
+ themeMode,
8
+ customColors,
9
+ isLoading: !isInitialized,
10
+ setThemeMode: (mode: ThemeMode) => {
11
+ void setThemeMode(mode);
12
+ },
13
+ setCustomColors: (colors: CustomThemeColors) => {
14
+ void setCustomColors(colors);
15
+ },
16
+ reset: () => {
17
+ void setThemeMode("light");
18
+ void setCustomColors(undefined);
19
+ },
20
+ };
21
21
  };
@@ -1,6 +1,6 @@
1
1
  import { useState, useCallback, useEffect } from "react";
2
2
  import { useAppearance } from "./useAppearance";
3
- import { CustomThemeColors } from "@umituz/react-native-design-system";
3
+ import type { CustomThemeColors, ThemeMode } from "@umituz/react-native-design-system";
4
4
 
5
5
  export const useAppearanceActions = () => {
6
6
  const { themeMode, customColors, setThemeMode, setCustomColors, reset } = useAppearance();
@@ -12,7 +12,7 @@ export const useAppearanceActions = () => {
12
12
  }
13
13
  }, [customColors]);
14
14
 
15
- const handleThemeSelect = useCallback((mode: any) => {
15
+ const handleThemeSelect = useCallback((mode: ThemeMode) => {
16
16
  setThemeMode(mode);
17
17
  }, [setThemeMode]);
18
18
 
@@ -28,6 +28,7 @@ export const useAppearanceActions = () => {
28
28
  }, [reset]);
29
29
 
30
30
  return {
31
+ themeMode,
31
32
  localCustomColors,
32
33
  handleThemeSelect,
33
34
  handleColorChange,
@@ -1,8 +0,0 @@
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
- }
@@ -1,34 +0,0 @@
1
- import { storageRepository, unwrap } from "@umituz/react-native-design-system";
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();
@@ -1,141 +0,0 @@
1
- # Appearance Services
2
-
3
- Service layer for appearance domain including system theme detection, validation, and appearance management.
4
-
5
- ## Purpose
6
-
7
- Provides business logic services for managing appearance settings including theme mode, custom colors, and system theme detection. Services encapsulate complex operations and provide a clean API for the domain.
8
-
9
- ## File Paths
10
-
11
- ```
12
- src/domains/appearance/infrastructure/services/
13
- ├── AppearanceService.ts # Main appearance management
14
- ├── SystemThemeDetectionService.ts # System theme detection
15
- └── ValidationService.ts # Color/theme validation
16
- ```
17
-
18
- ## Strategy
19
-
20
- 1. **Service Encapsulation**: Encapsulate complex appearance logic in service classes
21
- 2. **System Integration**: Detect and respond to system theme changes
22
- 3. **Validation First**: Validate all appearance changes before applying
23
- 4. **Event-Driven**: Use event listeners for system theme changes
24
- 5. **Type Safety**: Provide strongly typed service interfaces
25
-
26
- ## Restrictions
27
-
28
- ### DO NOT
29
-
30
- - ❌ DO NOT include UI components or React hooks in services
31
- - ❌ DO NOT directly access storage; use repositories
32
- - ❌ DO NOT mix validation logic with business logic
33
- - ❌ DO NOT create circular dependencies between services
34
- - ❌ DO NOT swallow validation errors
35
-
36
- ### NEVER
37
-
38
- - ❌ NEVER apply invalid color values
39
- - ❌ NEVER assume system theme is available
40
- - ❌ EVER bypass validation for any reason
41
- - ❌ EVER store raw hex values without validation
42
-
43
- ### AVOID
44
-
45
- - ❌ AVOID creating god services that do too much
46
- - ❌ AVOID tight coupling between services
47
- - ❌ AVOID synchronous operations for appearance changes
48
- - ❌ AVOID ignoring system theme change events
49
-
50
- ## Rules
51
-
52
- ### ALWAYS
53
-
54
- - ✅ ALWAYS validate theme modes before applying
55
- - ✅ ALWAYS validate hex color format before applying
56
- - ✅ ALWAYS handle system theme unsubscription
57
- - ✅ ALWAYS return typed results from service methods
58
- - ✅ ALWAYS handle service errors gracefully
59
-
60
- ### MUST
61
-
62
- - ✅ MUST validate all inputs before processing
63
- - ✅ MUST provide clear error messages for validation failures
64
- - ✅ MUST clean up event listeners on cleanup
65
- - ✅ MUST respect user preferences over system defaults
66
-
67
- ### SHOULD
68
-
69
- - ✅ SHOULD provide reactive interfaces for theme changes
70
- - ✅ SHOULD cache theme detection results
71
- - ✅ SHOULD offer batch operations for multiple changes
72
- - ✅ SHOULD log important service operations
73
-
74
- ## AI Agent Guidelines
75
-
76
- 1. **When creating services**: Keep them focused and single-purpose
77
- 2. **When adding validation**: Provide clear, actionable error messages
78
- 3. **When detecting system theme**: Use native APIs with fallbacks
79
- 4. **When managing colors**: Validate hex format (#RRGGBB) before applying
80
- 5. **When handling errors**: Transform technical errors into user-friendly messages
81
-
82
- ## Services Reference
83
-
84
- ### AppearanceService
85
-
86
- Main service for managing appearance settings including theme mode, custom colors, and system theme detection.
87
-
88
- **Location**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/domains/appearance/infrastructure/services/AppearanceService.ts`
89
-
90
- **Methods**:
91
- - `getThemeMode(): Promise<'light' | 'dark' | 'auto'>` - Get current theme mode
92
- - `setThemeMode(mode: 'light' | 'dark' | 'auto'): Promise<void>` - Set theme mode
93
- - `getCustomColors(): Promise<ColorPalette | undefined>` - Get custom colors
94
- - `setCustomColors(colors: ColorPalette): Promise<void>` - Set custom colors
95
- - `resetColors(): Promise<void>` - Reset to default colors
96
-
97
- ### SystemThemeDetectionService
98
-
99
- Service for detecting and monitoring system theme changes.
100
-
101
- **Location**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/domains/appearance/infrastructure/services/SystemThemeDetectionService.ts`
102
-
103
- **Methods**:
104
- - `getSystemTheme(): 'light' | 'dark' | null` - Get current system theme
105
- - `listen(callback: (theme: 'light' | 'dark') => void): () => void` - Listen for changes
106
-
107
- ### ValidationService
108
-
109
- Service for validating appearance settings.
110
-
111
- **Location**: `/Users/umituz/Desktop/github/umituz/apps/artificial_intelligence/npm-packages/react-native-settings/src/domains/appearance/infrastructure/services/ValidationService.ts`
112
-
113
- **Methods**:
114
- - `validateThemeMode(mode: string): boolean` - Validate theme mode
115
- - `validateColor(color: string): boolean` - Validate hex color
116
- - `validateColorPalette(palette: ColorPalette): boolean` - Validate complete palette
117
-
118
- ## Color Palette Structure
119
-
120
- **Primary**: Main brand color (#FF5722)
121
- **Secondary**: Secondary brand color (#2196F3)
122
- **Accent**: Highlight color (#FFC107)
123
- **Background**: Background color (#FFFFFF)
124
- **Surface**: Surface/card color (#F5F5F5)
125
- **Error**: Error state color (#F44336)
126
- **Success**: Success state color (#4CAF50)
127
- **Warning**: Warning state color (#FF9800)
128
-
129
- ## Best Practices
130
-
131
- 1. **Validation**: Always validate colors before saving
132
- 2. **System Theme**: Respect system theme when mode is 'auto'
133
- 3. **Cleanup**: Unsubscribe from theme listeners on unmount
134
- 4. **Error Handling**: Handle invalid colors gracefully
135
- 5. **Hex Format**: Use proper hex color format (#RRGGBB)
136
- 6. **Persistence**: Save theme changes immediately
137
- 7. **Performance**: Cache theme detection results
138
-
139
- ## License
140
-
141
- MIT
@@ -1,51 +0,0 @@
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();
@@ -1,73 +0,0 @@
1
- /**
2
- * System Theme Detection Utilities
3
- *
4
- * Utilities for detecting device theme preferences
5
- */
6
-
7
- import { Appearance, Platform } from 'react-native';
8
- import type { ThemeMode } from '@umituz/react-native-design-system';
9
-
10
- declare const window: any;
11
-
12
- /**
13
- * Get system theme mode from device settings
14
- * @returns System theme mode ('light' | 'dark' | null)
15
- */
16
- export const getSystemTheme = (): ThemeMode | null => {
17
- try {
18
- // On web, use matchMedia
19
- if (Platform.OS === 'web') {
20
- if (typeof window !== 'undefined' && (window as any).matchMedia) {
21
- const darkModeQuery = (window as any).matchMedia('(prefers-color-scheme: dark)');
22
- if (darkModeQuery.matches) {
23
- return 'dark';
24
- }
25
- return 'light';
26
- }
27
- }
28
-
29
- // On native platforms, use Appearance API
30
- const colorScheme = Appearance.getColorScheme();
31
- return colorScheme === 'dark' ? 'dark' : 'light';
32
- } catch {
33
- return null;
34
- }
35
- };
36
-
37
- /**
38
- * Check if system theme is dark
39
- * @returns true if system prefers dark mode
40
- */
41
- export const isSystemThemeDark = (): boolean => {
42
- return getSystemTheme() === 'dark';
43
- };
44
-
45
- /**
46
- * Check if system theme is light
47
- * @returns true if system prefers light mode
48
- */
49
- export const isSystemThemeLight = (): boolean => {
50
- return getSystemTheme() === 'light';
51
- };
52
-
53
- /**
54
- * Add system theme change listener
55
- * @param callback - Function to call when theme changes
56
- * @returns Cleanup function to remove listener
57
- */
58
- export const addSystemThemeListener = (
59
- callback: (themeMode: ThemeMode) => void,
60
- ): (() => void) => {
61
- try {
62
- const subscription = Appearance.addChangeListener(({ colorScheme }) => {
63
- const themeMode: ThemeMode = colorScheme === 'dark' ? 'dark' : 'light';
64
- callback(themeMode);
65
- });
66
-
67
- return () => {
68
- subscription?.remove();
69
- };
70
- } catch {
71
- return () => { }; // Return empty cleanup function
72
- }
73
- };
@@ -1,91 +0,0 @@
1
- /**
2
- * Appearance Validation Utilities
3
- *
4
- * Validation functions for appearance settings and colors
5
- */
6
-
7
- import type { ThemeMode, CustomThemeColors } from '@umituz/react-native-design-system';
8
-
9
- /**
10
- * Validate theme mode
11
- * @param mode - Theme mode to validate
12
- * @returns true if valid theme mode
13
- */
14
- export const isValidThemeMode = (mode: string): mode is ThemeMode => {
15
- return mode === 'light' || mode === 'dark';
16
- };
17
-
18
- /**
19
- * Validate hex color format
20
- * @param color - Color string to validate
21
- * @returns true if valid hex color
22
- */
23
- export const isValidHexColor = (color: string): boolean => {
24
- if (!color || typeof color !== 'string') {
25
- return false;
26
- }
27
-
28
- const hexRegex = /^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/;
29
- return hexRegex.test(color);
30
- };
31
-
32
- /**
33
- * Validate custom colors object
34
- * @param colors - Custom colors to validate
35
- * @returns Validation result with errors
36
- */
37
- export const validateCustomColors = (
38
- colors: CustomThemeColors
39
- ): { isValid: boolean; errors: string[] } => {
40
- const errors: string[] = [];
41
-
42
- // Check each color if provided
43
- const colorFields: (keyof CustomThemeColors)[] = [
44
- 'primary', 'primaryLight', 'primaryDark',
45
- 'secondary', 'secondaryLight', 'secondaryDark',
46
- 'accent', 'accentLight', 'accentDark',
47
- 'buttonPrimary', 'buttonSecondary'
48
- ];
49
-
50
- for (const field of colorFields) {
51
- const color = colors[field];
52
- if (color && !isValidHexColor(color)) {
53
- errors.push(`Invalid ${field} color: ${color}`);
54
- }
55
- }
56
-
57
- return {
58
- isValid: errors.length === 0,
59
- errors
60
- };
61
- };
62
-
63
- /**
64
- * Validate appearance settings
65
- * @param settings - Settings to validate
66
- * @returns Validation result with errors
67
- */
68
- export const validateAppearanceSettings = (settings: {
69
- themeMode?: string;
70
- customColors?: CustomThemeColors;
71
- }): { isValid: boolean; errors: string[] } => {
72
- const errors: string[] = [];
73
-
74
- // Validate theme mode
75
- if (settings.themeMode && !isValidThemeMode(settings.themeMode)) {
76
- errors.push(`Invalid theme mode: ${settings.themeMode}`);
77
- }
78
-
79
- // Validate custom colors
80
- if (settings.customColors) {
81
- const colorValidation = validateCustomColors(settings.customColors);
82
- if (!colorValidation.isValid) {
83
- errors.push(...colorValidation.errors);
84
- }
85
- }
86
-
87
- return {
88
- isValid: errors.length === 0,
89
- errors
90
- };
91
- };
@@ -1,65 +0,0 @@
1
- import { useMutation, useQueryClient } from "@umituz/react-native-design-system";
2
- import { getAppearanceService } from "../../../infrastructure/services/appearanceService";
3
- import { appearanceKeys } from "../queries/useAppearanceQuery";
4
- import { ThemeMode, CustomThemeColors } from "@umituz/react-native-design-system";
5
- import type { AppearanceSettings } from "../../../types";
6
-
7
- export const useAppearanceMutations = () => {
8
- const queryClient = useQueryClient();
9
- const service = getAppearanceService();
10
-
11
- const updateThemeMutation = useMutation({
12
- mutationFn: (mode: ThemeMode) => service.setThemeMode(mode),
13
- onMutate: async (mode: ThemeMode) => {
14
- await queryClient.cancelQueries({ queryKey: appearanceKeys.settings() });
15
- const previousData = queryClient.getQueryData<AppearanceSettings>(appearanceKeys.settings());
16
- queryClient.setQueryData<AppearanceSettings>(appearanceKeys.settings(), (old) => ({
17
- ...old,
18
- themeMode: mode,
19
- } as AppearanceSettings));
20
- return { previousData };
21
- },
22
- onError: (_err, _mode, context) => {
23
- if (context?.previousData) {
24
- queryClient.setQueryData(appearanceKeys.settings(), context.previousData);
25
- }
26
- },
27
- onSettled: () => {
28
- void queryClient.invalidateQueries({ queryKey: appearanceKeys.settings() });
29
- },
30
- });
31
-
32
- const updateColorsMutation = useMutation({
33
- mutationFn: (colors: CustomThemeColors) => service.setCustomColors(colors),
34
- onMutate: async (colors: CustomThemeColors) => {
35
- await queryClient.cancelQueries({ queryKey: appearanceKeys.settings() });
36
- const previousData = queryClient.getQueryData<AppearanceSettings>(appearanceKeys.settings());
37
- queryClient.setQueryData<AppearanceSettings>(appearanceKeys.settings(), (old) => ({
38
- ...old,
39
- customColors: { ...old?.customColors, ...colors },
40
- } as AppearanceSettings));
41
- return { previousData };
42
- },
43
- onError: (_err, _colors, context) => {
44
- if (context?.previousData) {
45
- queryClient.setQueryData(appearanceKeys.settings(), context.previousData);
46
- }
47
- },
48
- onSettled: () => {
49
- void queryClient.invalidateQueries({ queryKey: appearanceKeys.settings() });
50
- },
51
- });
52
-
53
- const resetAppearanceMutation = useMutation({
54
- mutationFn: () => service.resetSettings(),
55
- onSettled: () => {
56
- void queryClient.invalidateQueries({ queryKey: appearanceKeys.settings() });
57
- },
58
- });
59
-
60
- return {
61
- updateThemeMutation,
62
- updateColorsMutation,
63
- resetAppearanceMutation,
64
- };
65
- };
@@ -1,15 +0,0 @@
1
- import { useQuery } from "@umituz/react-native-design-system";
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
- };