@umituz/react-native-settings 4.12.0 → 4.15.0
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 +1 -1
- package/src/domain/repositories/ISettingsRepository.ts +48 -0
- package/src/index.ts +5 -1
- package/src/presentation/components/DevSettingsSection.tsx +7 -2
- package/src/presentation/screens/components/SettingsContent.tsx +22 -0
- package/src/presentation/screens/hooks/useFeatureDetection.ts +19 -4
- package/src/presentation/screens/types/FeatureConfig.ts +40 -0
- package/src/presentation/screens/types/SettingsConfig.ts +8 -0
- package/src/presentation/screens/types/index.ts +1 -0
- package/src/presentation/screens/utils/normalizeConfig.ts +6 -0
package/package.json
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Repository Interface and Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for settings storage operations
|
|
5
|
+
* and the core types used throughout the settings domain.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* User settings data structure
|
|
10
|
+
*/
|
|
11
|
+
export interface UserSettings {
|
|
12
|
+
userId: string;
|
|
13
|
+
theme: 'light' | 'dark' | 'auto';
|
|
14
|
+
language: string;
|
|
15
|
+
notificationsEnabled: boolean;
|
|
16
|
+
emailNotifications: boolean;
|
|
17
|
+
pushNotifications: boolean;
|
|
18
|
+
soundEnabled: boolean;
|
|
19
|
+
vibrationEnabled: boolean;
|
|
20
|
+
privacyMode: boolean;
|
|
21
|
+
updatedAt: Date;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Settings operation result
|
|
26
|
+
*/
|
|
27
|
+
export interface SettingsResult<T> {
|
|
28
|
+
success: boolean;
|
|
29
|
+
data?: T;
|
|
30
|
+
error?: SettingsError;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Settings error types
|
|
35
|
+
*/
|
|
36
|
+
export interface SettingsError {
|
|
37
|
+
code: string;
|
|
38
|
+
message: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Settings repository interface
|
|
43
|
+
*/
|
|
44
|
+
export interface ISettingsRepository {
|
|
45
|
+
getSettings(userId: string): Promise<SettingsResult<UserSettings>>;
|
|
46
|
+
saveSettings(settings: UserSettings): Promise<SettingsResult<void>>;
|
|
47
|
+
deleteSettings(userId: string): Promise<SettingsResult<void>>;
|
|
48
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -50,7 +50,11 @@ export type {
|
|
|
50
50
|
// PRESENTATION LAYER - Types
|
|
51
51
|
// =============================================================================
|
|
52
52
|
|
|
53
|
-
export type {
|
|
53
|
+
export type {
|
|
54
|
+
SettingsConfig,
|
|
55
|
+
CustomSettingsSection,
|
|
56
|
+
SubscriptionConfig,
|
|
57
|
+
} from './presentation/screens/types';
|
|
54
58
|
|
|
55
59
|
// =============================================================================
|
|
56
60
|
// PRESENTATION LAYER - Components
|
|
@@ -73,8 +73,13 @@ export const DevSettingsSection: React.FC<DevSettingsProps> = ({
|
|
|
73
73
|
style: "destructive",
|
|
74
74
|
onPress: async () => {
|
|
75
75
|
try {
|
|
76
|
-
// Clear all storage
|
|
77
|
-
await storageRepository.clearAll();
|
|
76
|
+
// Clear all storage and check result
|
|
77
|
+
const result = await storageRepository.clearAll();
|
|
78
|
+
|
|
79
|
+
if (!result.success) {
|
|
80
|
+
Alert.alert(t.errorTitle, t.errorMessage);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
78
83
|
|
|
79
84
|
// If callback provided, call it (e.g., reload app)
|
|
80
85
|
if (onAfterClear) {
|
|
@@ -32,6 +32,18 @@ try {
|
|
|
32
32
|
// Package not available
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// Optional subscription component
|
|
36
|
+
let SubscriptionSection: React.ComponentType<any> | null = null;
|
|
37
|
+
try {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
39
|
+
const module = require("@umituz/react-native-subscription");
|
|
40
|
+
if (module?.SubscriptionSection) {
|
|
41
|
+
SubscriptionSection = module.SubscriptionSection;
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// Package not available
|
|
45
|
+
}
|
|
46
|
+
|
|
35
47
|
interface SettingsContentProps {
|
|
36
48
|
normalizedConfig: NormalizedConfig;
|
|
37
49
|
config?: any; // Original config for emptyStateText
|
|
@@ -43,6 +55,7 @@ interface SettingsContentProps {
|
|
|
43
55
|
legal: boolean;
|
|
44
56
|
disclaimer: boolean;
|
|
45
57
|
userProfile: boolean;
|
|
58
|
+
subscription: boolean;
|
|
46
59
|
};
|
|
47
60
|
showUserProfile?: boolean;
|
|
48
61
|
userProfile?: {
|
|
@@ -88,6 +101,7 @@ export const SettingsContent: React.FC<SettingsContentProps> = ({
|
|
|
88
101
|
features.about ||
|
|
89
102
|
features.legal ||
|
|
90
103
|
features.disclaimer ||
|
|
104
|
+
features.subscription ||
|
|
91
105
|
customSections.length > 0,
|
|
92
106
|
[features, customSections.length]
|
|
93
107
|
);
|
|
@@ -125,6 +139,14 @@ export const SettingsContent: React.FC<SettingsContentProps> = ({
|
|
|
125
139
|
</View>
|
|
126
140
|
)}
|
|
127
141
|
|
|
142
|
+
{features.subscription &&
|
|
143
|
+
SubscriptionSection &&
|
|
144
|
+
normalizedConfig.subscription.config?.sectionConfig && (
|
|
145
|
+
<SubscriptionSection
|
|
146
|
+
config={normalizedConfig.subscription.config.sectionConfig}
|
|
147
|
+
/>
|
|
148
|
+
)}
|
|
149
|
+
|
|
128
150
|
{features.appearance && (
|
|
129
151
|
<AppearanceSection
|
|
130
152
|
config={{
|
|
@@ -61,10 +61,19 @@ export function useFeatureDetection(
|
|
|
61
61
|
},
|
|
62
62
|
) {
|
|
63
63
|
return useMemo(() => {
|
|
64
|
-
const {
|
|
65
|
-
|
|
64
|
+
const {
|
|
65
|
+
appearance,
|
|
66
|
+
language,
|
|
67
|
+
notifications,
|
|
68
|
+
about,
|
|
69
|
+
legal,
|
|
70
|
+
disclaimer,
|
|
71
|
+
userProfile,
|
|
72
|
+
subscription,
|
|
73
|
+
} = normalizedConfig;
|
|
66
74
|
|
|
67
|
-
const notificationServiceAvailable =
|
|
75
|
+
const notificationServiceAvailable =
|
|
76
|
+
options?.notificationServiceAvailable ?? notificationService !== null;
|
|
68
77
|
|
|
69
78
|
return {
|
|
70
79
|
appearance:
|
|
@@ -106,8 +115,14 @@ export function useFeatureDetection(
|
|
|
106
115
|
disclaimer.enabled &&
|
|
107
116
|
(disclaimer.config?.enabled === true ||
|
|
108
117
|
(disclaimer.config?.enabled !== false &&
|
|
109
|
-
hasNavigationScreen(
|
|
118
|
+
hasNavigationScreen(
|
|
119
|
+
navigation,
|
|
120
|
+
disclaimer.config?.route || "Disclaimer",
|
|
121
|
+
))),
|
|
110
122
|
userProfile: userProfile.enabled,
|
|
123
|
+
subscription:
|
|
124
|
+
subscription.enabled &&
|
|
125
|
+
subscription.config?.sectionConfig !== undefined,
|
|
111
126
|
};
|
|
112
127
|
}, [normalizedConfig, navigation, options]);
|
|
113
128
|
}
|
|
@@ -128,3 +128,43 @@ export interface UserProfileConfig {
|
|
|
128
128
|
/** Navigation route for account settings (shows chevron if set) */
|
|
129
129
|
accountSettingsRoute?: string;
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Subscription Settings Configuration
|
|
134
|
+
* App must provide all data via sectionConfig (no internal fetch)
|
|
135
|
+
*/
|
|
136
|
+
export interface SubscriptionConfig {
|
|
137
|
+
/** Show subscription section */
|
|
138
|
+
enabled?: FeatureVisibility;
|
|
139
|
+
/** Section configuration (app provides all data) */
|
|
140
|
+
sectionConfig?: {
|
|
141
|
+
statusType: "active" | "expired" | "none";
|
|
142
|
+
isPremium: boolean;
|
|
143
|
+
expirationDate?: string | null;
|
|
144
|
+
purchaseDate?: string | null;
|
|
145
|
+
isLifetime?: boolean;
|
|
146
|
+
daysRemaining?: number | null;
|
|
147
|
+
credits?: Array<{
|
|
148
|
+
id: string;
|
|
149
|
+
label: string;
|
|
150
|
+
current: number;
|
|
151
|
+
total: number;
|
|
152
|
+
}>;
|
|
153
|
+
translations: {
|
|
154
|
+
title: string;
|
|
155
|
+
statusLabel: string;
|
|
156
|
+
expiresLabel: string;
|
|
157
|
+
purchasedLabel: string;
|
|
158
|
+
creditsTitle?: string;
|
|
159
|
+
remainingLabel?: string;
|
|
160
|
+
manageButton?: string;
|
|
161
|
+
upgradeButton?: string;
|
|
162
|
+
lifetimeLabel?: string;
|
|
163
|
+
statusActive?: string;
|
|
164
|
+
statusExpired?: string;
|
|
165
|
+
statusFree?: string;
|
|
166
|
+
};
|
|
167
|
+
onManageSubscription?: () => void;
|
|
168
|
+
onUpgrade?: () => void;
|
|
169
|
+
};
|
|
170
|
+
}
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
LegalConfig,
|
|
13
13
|
DisclaimerConfig,
|
|
14
14
|
UserProfileConfig,
|
|
15
|
+
SubscriptionConfig,
|
|
15
16
|
} from "./FeatureConfig";
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -88,6 +89,13 @@ export interface SettingsConfig {
|
|
|
88
89
|
*/
|
|
89
90
|
userProfile?: boolean | UserProfileConfig;
|
|
90
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Subscription/Premium settings
|
|
94
|
+
* App must provide all data via sectionConfig
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
subscription?: FeatureVisibility | SubscriptionConfig;
|
|
98
|
+
|
|
91
99
|
/**
|
|
92
100
|
* Custom empty state text when no settings are available
|
|
93
101
|
*/
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
LegalConfig,
|
|
13
13
|
DisclaimerConfig,
|
|
14
14
|
UserProfileConfig,
|
|
15
|
+
SubscriptionConfig,
|
|
15
16
|
SettingsConfig,
|
|
16
17
|
} from "../types";
|
|
17
18
|
|
|
@@ -44,6 +45,10 @@ export interface NormalizedConfig {
|
|
|
44
45
|
enabled: boolean;
|
|
45
46
|
config?: UserProfileConfig;
|
|
46
47
|
};
|
|
48
|
+
subscription: {
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
config?: SubscriptionConfig;
|
|
51
|
+
};
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
/**
|
|
@@ -85,6 +90,7 @@ export function normalizeSettingsConfig(
|
|
|
85
90
|
legal: normalizeConfigValue(config?.legal, "auto"),
|
|
86
91
|
disclaimer: normalizeConfigValue(config?.disclaimer, false),
|
|
87
92
|
userProfile: normalizeConfigValue(config?.userProfile, false),
|
|
93
|
+
subscription: normalizeConfigValue(config?.subscription, false),
|
|
88
94
|
};
|
|
89
95
|
}
|
|
90
96
|
|