@umituz/react-native-settings 5.3.51 → 5.3.53
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/account.d.ts +20 -18
- package/dist/domains/feedback/infrastructure/useFeatureRequests.d.ts +4 -0
- package/dist/presentation/hooks/useSettingsScreenConfig.d.ts +1 -2
- package/package.json +4 -2
- package/src/account.ts +26 -22
- package/src/domains/feedback/infrastructure/useFeatureRequests.ts +126 -43
- package/src/presentation/hooks/useSettingsScreenConfig.ts +32 -25
- package/dist/domains/feedback/domain/repositories/IFeedbackRepository.d.ts +0 -20
- package/dist/presentation/utils/faqTranslator.d.ts +0 -3
package/dist/account.d.ts
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @umituz/react-native-settings/account
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* NOTE: Auth has been removed from this application.
|
|
5
|
+
* This file now provides empty exports for backward compatibility.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* import {
|
|
9
|
-
* useSettingsScreenConfig,
|
|
10
|
-
* AccountScreen,
|
|
11
|
-
* ProfileSection,
|
|
12
|
-
* } from '@umituz/react-native-settings/account';
|
|
13
|
-
*
|
|
14
|
-
* // Pass AccountScreen and ProfileSection as props to SettingsStackNavigator:
|
|
15
|
-
* <SettingsStackNavigator
|
|
16
|
-
* AccountScreenComponent={AccountScreen}
|
|
17
|
-
* ProfileSectionComponent={ProfileSection}
|
|
18
|
-
* ...
|
|
19
|
-
* />
|
|
7
|
+
* Apps that use @umituz/react-native-auth should import directly from that package:
|
|
8
|
+
* import { AccountScreen, ProfileSection } from '@umituz/react-native-auth';
|
|
20
9
|
*/
|
|
21
|
-
export
|
|
22
|
-
export
|
|
23
|
-
export
|
|
10
|
+
export declare const AccountScreen: React.ComponentType<any> | null;
|
|
11
|
+
export declare const ProfileSection: React.ComponentType<any> | null;
|
|
12
|
+
export declare const useAuth: () => {
|
|
13
|
+
user: any;
|
|
14
|
+
loading: boolean;
|
|
15
|
+
isAuthReady: boolean;
|
|
16
|
+
isAnonymous: boolean;
|
|
17
|
+
};
|
|
18
|
+
export declare const useUserProfile: () => any;
|
|
19
|
+
export declare const useAuthHandlers: () => {
|
|
20
|
+
handleRatePress: () => Promise<void>;
|
|
21
|
+
handleSignOut: () => Promise<void>;
|
|
22
|
+
handleDeleteAccount: () => Promise<void>;
|
|
23
|
+
handleSignIn: () => Promise<void>;
|
|
24
|
+
};
|
|
25
|
+
export type AccountScreenConfig = any;
|
|
24
26
|
export { useSettingsScreenConfig } from './presentation/hooks/useSettingsScreenConfig';
|
|
25
27
|
export type { UseSettingsScreenConfigParams, SettingsScreenConfigResult, SettingsFeatures, } from './presentation/hooks/useSettingsScreenConfig';
|
|
26
28
|
export type { AccountConfig } from './presentation/navigation/types';
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* useFeatureRequests Hook
|
|
3
3
|
* Internal hook — fetches, votes, submits feature requests via Firestore
|
|
4
4
|
* Works with both authenticated and anonymous users
|
|
5
|
+
*
|
|
6
|
+
* FIREBASE LAZY LOADING:
|
|
7
|
+
* Firebase is lazy-loaded to avoid hard dependency.
|
|
8
|
+
* If @umituz/react-native-firebase is not installed, features are disabled gracefully.
|
|
5
9
|
*/
|
|
6
10
|
import type { FeatureRequestItem, VoteType } from "../domain/entities/FeatureRequestEntity";
|
|
7
11
|
export interface UseFeatureRequestsResult {
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* useSettingsScreenConfig Hook
|
|
3
3
|
*
|
|
4
4
|
* One-stop hook for settings screen configuration.
|
|
5
|
-
*
|
|
6
|
-
* Apps pass subscription config from subscription package.
|
|
5
|
+
* Auth has been removed - this is a no-auth version.
|
|
7
6
|
*/
|
|
8
7
|
import type { SettingsConfig, SettingsTranslations } from "../screens/types";
|
|
9
8
|
import type { FeedbackFormData } from "../utils/config-creators";
|
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.53",
|
|
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": "./dist/index.d.ts",
|
|
@@ -140,6 +140,9 @@
|
|
|
140
140
|
"peerDependenciesMeta": {
|
|
141
141
|
"@umituz/react-native-auth": {
|
|
142
142
|
"optional": true
|
|
143
|
+
},
|
|
144
|
+
"@umituz/react-native-firebase": {
|
|
145
|
+
"optional": true
|
|
143
146
|
}
|
|
144
147
|
},
|
|
145
148
|
"devDependencies": {
|
|
@@ -166,7 +169,6 @@
|
|
|
166
169
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
167
170
|
"eslint-plugin-react-native": "^5.0.0",
|
|
168
171
|
"expo-apple-authentication": "^8.0.8",
|
|
169
|
-
"expo-auth-session": "^5.0.0",
|
|
170
172
|
"expo-clipboard": "^8.0.8",
|
|
171
173
|
"expo-crypto": "^15.0.8",
|
|
172
174
|
"expo-device": "~7.0.0",
|
package/src/account.ts
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @umituz/react-native-settings/account
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* NOTE: Auth has been removed from this application.
|
|
5
|
+
* This file now provides empty exports for backward compatibility.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* import {
|
|
9
|
-
* useSettingsScreenConfig,
|
|
10
|
-
* AccountScreen,
|
|
11
|
-
* ProfileSection,
|
|
12
|
-
* } from '@umituz/react-native-settings/account';
|
|
13
|
-
*
|
|
14
|
-
* // Pass AccountScreen and ProfileSection as props to SettingsStackNavigator:
|
|
15
|
-
* <SettingsStackNavigator
|
|
16
|
-
* AccountScreenComponent={AccountScreen}
|
|
17
|
-
* ProfileSectionComponent={ProfileSection}
|
|
18
|
-
* ...
|
|
19
|
-
* />
|
|
7
|
+
* Apps that use @umituz/react-native-auth should import directly from that package:
|
|
8
|
+
* import { AccountScreen, ProfileSection } from '@umituz/react-native-auth';
|
|
20
9
|
*/
|
|
21
10
|
|
|
22
|
-
//
|
|
23
|
-
export
|
|
11
|
+
// Empty exports for backward compatibility
|
|
12
|
+
export const AccountScreen: React.ComponentType<any> | null = null;
|
|
13
|
+
export const ProfileSection: React.ComponentType<any> | null = null;
|
|
14
|
+
|
|
15
|
+
// Stub hooks that return default values
|
|
16
|
+
export const useAuth = () => ({
|
|
17
|
+
user: null,
|
|
18
|
+
loading: false,
|
|
19
|
+
isAuthReady: true,
|
|
20
|
+
isAnonymous: true,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const useUserProfile = () => null;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
export const useAuthHandlers = () => ({
|
|
26
|
+
handleRatePress: async () => {},
|
|
27
|
+
handleSignOut: async () => {},
|
|
28
|
+
handleDeleteAccount: async () => {},
|
|
29
|
+
handleSignIn: async () => {},
|
|
30
|
+
});
|
|
27
31
|
|
|
28
|
-
//
|
|
29
|
-
export type
|
|
32
|
+
// Empty types
|
|
33
|
+
export type AccountScreenConfig = any;
|
|
30
34
|
|
|
31
|
-
// Base hook (
|
|
35
|
+
// Base hook (no auth version)
|
|
32
36
|
export { useSettingsScreenConfig } from './presentation/hooks/useSettingsScreenConfig';
|
|
33
37
|
|
|
34
38
|
// Re-export types
|
|
@@ -2,26 +2,16 @@
|
|
|
2
2
|
* useFeatureRequests Hook
|
|
3
3
|
* Internal hook — fetches, votes, submits feature requests via Firestore
|
|
4
4
|
* Works with both authenticated and anonymous users
|
|
5
|
+
*
|
|
6
|
+
* FIREBASE LAZY LOADING:
|
|
7
|
+
* Firebase is lazy-loaded to avoid hard dependency.
|
|
8
|
+
* If @umituz/react-native-firebase is not installed, features are disabled gracefully.
|
|
5
9
|
*/
|
|
6
10
|
|
|
7
11
|
import { useState, useEffect, useCallback, useRef } from "react";
|
|
8
12
|
import { Platform } from "react-native";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
collection,
|
|
12
|
-
doc,
|
|
13
|
-
getDocs,
|
|
14
|
-
getDoc,
|
|
15
|
-
setDoc,
|
|
16
|
-
addDoc,
|
|
17
|
-
updateDoc,
|
|
18
|
-
deleteDoc,
|
|
19
|
-
increment,
|
|
20
|
-
orderBy,
|
|
21
|
-
query,
|
|
22
|
-
serverTimestamp,
|
|
23
|
-
} from "firebase/firestore";
|
|
24
|
-
import { getFirestore } from "@umituz/react-native-firebase";
|
|
13
|
+
import * as Crypto from "expo-crypto";
|
|
14
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
25
15
|
import type {
|
|
26
16
|
FeatureRequestItem,
|
|
27
17
|
FeatureRequestStatus,
|
|
@@ -29,6 +19,84 @@ import type {
|
|
|
29
19
|
} from "../domain/entities/FeatureRequestEntity";
|
|
30
20
|
|
|
31
21
|
const COLLECTION = "feature_requests";
|
|
22
|
+
const ANONYMOUS_USER_ID_KEY = "@anonymous_user_id";
|
|
23
|
+
|
|
24
|
+
// Lazy-loaded Firebase modules
|
|
25
|
+
let firebaseModules: {
|
|
26
|
+
getFirestore: () => any;
|
|
27
|
+
collection: any;
|
|
28
|
+
doc: any;
|
|
29
|
+
getDocs: any;
|
|
30
|
+
getDoc: any;
|
|
31
|
+
setDoc: any;
|
|
32
|
+
addDoc: any;
|
|
33
|
+
updateDoc: any;
|
|
34
|
+
deleteDoc: any;
|
|
35
|
+
increment: any;
|
|
36
|
+
orderBy: any;
|
|
37
|
+
query: any;
|
|
38
|
+
serverTimestamp: any;
|
|
39
|
+
} | null = null;
|
|
40
|
+
|
|
41
|
+
function loadFirebase(): typeof firebaseModules {
|
|
42
|
+
if (firebaseModules !== null) return firebaseModules;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// Lazy load Firebase only when needed
|
|
46
|
+
const firebaseModule = require("@umituz/react-native-firebase");
|
|
47
|
+
const firestoreModule = require("firebase/firestore");
|
|
48
|
+
|
|
49
|
+
firebaseModules = {
|
|
50
|
+
getFirestore: firebaseModule.getFirestore,
|
|
51
|
+
collection: firestoreModule.collection,
|
|
52
|
+
doc: firestoreModule.doc,
|
|
53
|
+
getDocs: firestoreModule.getDocs,
|
|
54
|
+
getDoc: firestoreModule.getDoc,
|
|
55
|
+
setDoc: firestoreModule.setDoc,
|
|
56
|
+
addDoc: firestoreModule.addDoc,
|
|
57
|
+
updateDoc: firestoreModule.updateDoc,
|
|
58
|
+
deleteDoc: firestoreModule.deleteDoc,
|
|
59
|
+
increment: firestoreModule.increment,
|
|
60
|
+
orderBy: firestoreModule.orderBy,
|
|
61
|
+
query: firestoreModule.query,
|
|
62
|
+
serverTimestamp: firestoreModule.serverTimestamp,
|
|
63
|
+
};
|
|
64
|
+
return firebaseModules;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
// Firebase not installed - return null to disable features
|
|
67
|
+
if (__DEV__) {
|
|
68
|
+
console.warn(
|
|
69
|
+
"[useFeatureRequests] @umituz/react-native-firebase not installed. Feature requests disabled.",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
firebaseModules = null;
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get or create a persistent anonymous user ID
|
|
79
|
+
*/
|
|
80
|
+
async function getAnonymousUserId(): Promise<string> {
|
|
81
|
+
try {
|
|
82
|
+
const existingId = await AsyncStorage.getItem(ANONYMOUS_USER_ID_KEY);
|
|
83
|
+
if (existingId) return existingId;
|
|
84
|
+
|
|
85
|
+
// Create a new anonymous ID using device UUID
|
|
86
|
+
const randomBytes = await Crypto.getRandomBytesAsync(16);
|
|
87
|
+
const newId = Array.from(randomBytes)
|
|
88
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
89
|
+
.join("");
|
|
90
|
+
|
|
91
|
+
await AsyncStorage.setItem(ANONYMOUS_USER_ID_KEY, newId);
|
|
92
|
+
return newId;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// Fallback to timestamp-based ID if crypto fails
|
|
95
|
+
const fallbackId = `anon_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
96
|
+
await AsyncStorage.setItem(ANONYMOUS_USER_ID_KEY, fallbackId);
|
|
97
|
+
return fallbackId;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
32
100
|
|
|
33
101
|
export interface UseFeatureRequestsResult {
|
|
34
102
|
requests: FeatureRequestItem[];
|
|
@@ -41,13 +109,19 @@ export interface UseFeatureRequestsResult {
|
|
|
41
109
|
}
|
|
42
110
|
|
|
43
111
|
export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
44
|
-
const
|
|
45
|
-
const userId = user?.uid ?? null;
|
|
112
|
+
const [userId, setUserId] = useState<string | null>(null);
|
|
46
113
|
|
|
47
114
|
const [requests, setRequests] = useState<FeatureRequestItem[]>([]);
|
|
48
115
|
const [userVotes, setUserVotes] = useState<Record<string, VoteType>>({});
|
|
49
116
|
const [isLoading, setIsLoading] = useState(true);
|
|
50
117
|
|
|
118
|
+
// Initialize anonymous user ID
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
getAnonymousUserId().then((id) => {
|
|
121
|
+
setUserId(id);
|
|
122
|
+
});
|
|
123
|
+
}, []);
|
|
124
|
+
|
|
51
125
|
// Ref to avoid stale closure in vote()
|
|
52
126
|
const userVotesRef = useRef(userVotes);
|
|
53
127
|
userVotesRef.current = userVotes;
|
|
@@ -56,7 +130,13 @@ export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
|
56
130
|
const votingInProgress = useRef(new Set<string>());
|
|
57
131
|
|
|
58
132
|
const fetchAll = useCallback(async () => {
|
|
59
|
-
const
|
|
133
|
+
const fb = loadFirebase();
|
|
134
|
+
if (!fb) {
|
|
135
|
+
setIsLoading(false);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const db = fb.getFirestore();
|
|
60
140
|
if (!db) {
|
|
61
141
|
setIsLoading(false);
|
|
62
142
|
return;
|
|
@@ -65,8 +145,8 @@ export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
|
65
145
|
try {
|
|
66
146
|
setIsLoading(true);
|
|
67
147
|
|
|
68
|
-
const q = query(collection(db, COLLECTION), orderBy("votes", "desc"));
|
|
69
|
-
const snapshot = await getDocs(q);
|
|
148
|
+
const q = fb.query(fb.collection(db, COLLECTION), fb.orderBy("votes", "desc"));
|
|
149
|
+
const snapshot = await fb.getDocs(q);
|
|
70
150
|
|
|
71
151
|
const items: FeatureRequestItem[] = snapshot.docs.map((d) => {
|
|
72
152
|
const data = d.data();
|
|
@@ -91,8 +171,8 @@ export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
|
91
171
|
// Fetch user votes in parallel (not N+1 sequential)
|
|
92
172
|
if (userId && snapshot.docs.length > 0) {
|
|
93
173
|
const votePromises = snapshot.docs.map(async (reqDoc) => {
|
|
94
|
-
const voteRef = doc(db, COLLECTION, reqDoc.id, "votes", userId);
|
|
95
|
-
const voteSnap = await getDoc(voteRef);
|
|
174
|
+
const voteRef = fb.doc(db, COLLECTION, reqDoc.id, "votes", userId);
|
|
175
|
+
const voteSnap = await fb.getDoc(voteRef);
|
|
96
176
|
if (voteSnap.exists()) {
|
|
97
177
|
return [reqDoc.id, voteSnap.data().type as VoteType] as const;
|
|
98
178
|
}
|
|
@@ -120,13 +200,14 @@ export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
|
120
200
|
}, [fetchAll]);
|
|
121
201
|
|
|
122
202
|
const vote = useCallback(async (requestId: string, type: VoteType) => {
|
|
123
|
-
|
|
203
|
+
const fb = loadFirebase();
|
|
204
|
+
if (!fb || !userId) return;
|
|
124
205
|
|
|
125
206
|
// Prevent rapid double-tap on the same request
|
|
126
207
|
if (votingInProgress.current.has(requestId)) return;
|
|
127
208
|
votingInProgress.current.add(requestId);
|
|
128
209
|
|
|
129
|
-
const db = getFirestore();
|
|
210
|
+
const db = fb.getFirestore();
|
|
130
211
|
if (!db) {
|
|
131
212
|
votingInProgress.current.delete(requestId);
|
|
132
213
|
return;
|
|
@@ -154,22 +235,22 @@ export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
|
154
235
|
);
|
|
155
236
|
|
|
156
237
|
try {
|
|
157
|
-
const voteRef = doc(db, COLLECTION, requestId, "votes", userId);
|
|
158
|
-
const requestRef = doc(db, COLLECTION, requestId);
|
|
159
|
-
const existing = await getDoc(voteRef);
|
|
238
|
+
const voteRef = fb.doc(db, COLLECTION, requestId, "votes", userId);
|
|
239
|
+
const requestRef = fb.doc(db, COLLECTION, requestId);
|
|
240
|
+
const existing = await fb.getDoc(voteRef);
|
|
160
241
|
|
|
161
242
|
if (existing.exists()) {
|
|
162
243
|
const prev = existing.data().type as VoteType;
|
|
163
244
|
if (prev === type) {
|
|
164
|
-
await deleteDoc(voteRef);
|
|
165
|
-
await updateDoc(requestRef, { votes: increment(type === "up" ? -1 : 1) });
|
|
245
|
+
await fb.deleteDoc(voteRef);
|
|
246
|
+
await fb.updateDoc(requestRef, { votes: fb.increment(type === "up" ? -1 : 1) });
|
|
166
247
|
} else {
|
|
167
|
-
await setDoc(voteRef, { type, votedAt: serverTimestamp() });
|
|
168
|
-
await updateDoc(requestRef, { votes: increment(type === "up" ? 2 : -2) });
|
|
248
|
+
await fb.setDoc(voteRef, { type, votedAt: fb.serverTimestamp() });
|
|
249
|
+
await fb.updateDoc(requestRef, { votes: fb.increment(type === "up" ? 2 : -2) });
|
|
169
250
|
}
|
|
170
251
|
} else {
|
|
171
|
-
await setDoc(voteRef, { type, votedAt: serverTimestamp() });
|
|
172
|
-
await updateDoc(requestRef, { votes: increment(type === "up" ? 1 : -1) });
|
|
252
|
+
await fb.setDoc(voteRef, { type, votedAt: fb.serverTimestamp() });
|
|
253
|
+
await fb.updateDoc(requestRef, { votes: fb.increment(type === "up" ? 1 : -1) });
|
|
173
254
|
}
|
|
174
255
|
} catch (error) {
|
|
175
256
|
if (__DEV__) console.warn("[useFeatureRequests] Vote failed:", error);
|
|
@@ -186,12 +267,14 @@ export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
|
186
267
|
}, [userId, fetchAll]);
|
|
187
268
|
|
|
188
269
|
const submitRequest = useCallback(async (data: { title: string; description: string; type: string; rating?: number }) => {
|
|
189
|
-
const
|
|
270
|
+
const fb = loadFirebase();
|
|
271
|
+
if (!fb) throw new Error("Firestore not available");
|
|
272
|
+
const db = fb.getFirestore();
|
|
190
273
|
if (!db) throw new Error("Firestore not available");
|
|
191
|
-
if (!userId) throw new Error("User not
|
|
274
|
+
if (!userId) throw new Error("User ID not available");
|
|
192
275
|
|
|
193
276
|
// Create the feature request
|
|
194
|
-
const docRef = await addDoc(collection(db, COLLECTION), {
|
|
277
|
+
const docRef = await fb.addDoc(fb.collection(db, COLLECTION), {
|
|
195
278
|
title: data.title,
|
|
196
279
|
description: data.description,
|
|
197
280
|
type: data.type || "feature_request",
|
|
@@ -199,21 +282,21 @@ export function useFeatureRequests(): UseFeatureRequestsResult {
|
|
|
199
282
|
votes: 1,
|
|
200
283
|
commentCount: 0,
|
|
201
284
|
createdBy: userId,
|
|
202
|
-
isAnonymous:
|
|
285
|
+
isAnonymous: true,
|
|
203
286
|
platform: Platform.OS,
|
|
204
287
|
rating: data.rating ?? null,
|
|
205
|
-
createdAt: serverTimestamp(),
|
|
206
|
-
updatedAt: serverTimestamp(),
|
|
288
|
+
createdAt: fb.serverTimestamp(),
|
|
289
|
+
updatedAt: fb.serverTimestamp(),
|
|
207
290
|
});
|
|
208
291
|
|
|
209
292
|
// Create the creator's upvote doc so votes count matches reality
|
|
210
|
-
await setDoc(doc(db, COLLECTION, docRef.id, "votes", userId), {
|
|
293
|
+
await fb.setDoc(fb.doc(db, COLLECTION, docRef.id, "votes", userId), {
|
|
211
294
|
type: "up" as VoteType,
|
|
212
|
-
votedAt: serverTimestamp(),
|
|
295
|
+
votedAt: fb.serverTimestamp(),
|
|
213
296
|
});
|
|
214
297
|
|
|
215
298
|
await fetchAll();
|
|
216
|
-
}, [userId,
|
|
299
|
+
}, [userId, fetchAll]);
|
|
217
300
|
|
|
218
301
|
return { requests, userVotes, isLoading, vote, submitRequest, reload: fetchAll, userId };
|
|
219
302
|
}
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
* useSettingsScreenConfig Hook
|
|
3
3
|
*
|
|
4
4
|
* One-stop hook for settings screen configuration.
|
|
5
|
-
*
|
|
6
|
-
* Apps pass subscription config from subscription package.
|
|
5
|
+
* Auth has been removed - this is a no-auth version.
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
8
|
import { useMemo } from "react";
|
|
10
|
-
import { useAuth, useUserProfile, useAuthHandlers } from "@umituz/react-native-auth";
|
|
11
9
|
import { createUserProfileDisplay } from "../utils/userProfileUtils";
|
|
12
10
|
import { createAccountConfig, type AccountTranslations } from "../utils/accountConfigUtils";
|
|
13
11
|
import { useSettingsConfigFactory } from "../utils/settingsConfigFactory";
|
|
@@ -67,12 +65,27 @@ export const useSettingsScreenConfig = (
|
|
|
67
65
|
subscription: showSubscription = true,
|
|
68
66
|
} = features;
|
|
69
67
|
|
|
70
|
-
|
|
71
|
-
const
|
|
68
|
+
// No-auth version - always ready
|
|
69
|
+
const loading = false;
|
|
70
|
+
const isAuthReady = true;
|
|
72
71
|
|
|
73
|
-
//
|
|
74
|
-
const
|
|
75
|
-
|
|
72
|
+
// Default handlers (no-ops for no-auth version)
|
|
73
|
+
const handleRatePress = useMemo(() => async () => {
|
|
74
|
+
// Default rate behavior - could be implemented with expo-store-review
|
|
75
|
+
console.warn("[useSettingsScreenConfig] Rate press handler not implemented in no-auth version");
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
78
|
+
const handleSignOut = useMemo(() => async () => {
|
|
79
|
+
// No-op in no-auth version
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
82
|
+
const handleDeleteAccount = useMemo(() => async () => {
|
|
83
|
+
// No-op in no-auth version
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
const handleSignIn = useMemo(() => async () => {
|
|
87
|
+
// No-op in no-auth version
|
|
88
|
+
}, []);
|
|
76
89
|
|
|
77
90
|
// Use settings config factory
|
|
78
91
|
const baseSettingsConfig = useSettingsConfigFactory({
|
|
@@ -133,30 +146,24 @@ export const useSettingsScreenConfig = (
|
|
|
133
146
|
return config;
|
|
134
147
|
}, [baseSettingsConfig, translations]);
|
|
135
148
|
|
|
149
|
+
// Empty user profile (no-auth version)
|
|
136
150
|
const userProfile = useMemo(() => createUserProfileDisplay({
|
|
137
|
-
profileData:
|
|
151
|
+
profileData: null,
|
|
138
152
|
onSignIn: handleSignIn,
|
|
139
|
-
}), [
|
|
153
|
+
}), [handleSignIn]);
|
|
140
154
|
|
|
155
|
+
// Minimal account config (no-auth version)
|
|
141
156
|
const accountConfig = useMemo(() => createAccountConfig({
|
|
142
|
-
displayName:
|
|
143
|
-
userId:
|
|
144
|
-
photoURL:
|
|
145
|
-
isAnonymous:
|
|
146
|
-
avatarUrl:
|
|
157
|
+
displayName: undefined,
|
|
158
|
+
userId: undefined,
|
|
159
|
+
photoURL: undefined,
|
|
160
|
+
isAnonymous: true,
|
|
161
|
+
avatarUrl: undefined,
|
|
147
162
|
onSignIn: handleSignIn,
|
|
148
163
|
onLogout: handleSignOut,
|
|
149
164
|
onDeleteAccount: handleDeleteAccount,
|
|
150
|
-
translations:
|
|
151
|
-
|
|
152
|
-
translations?.account?.logoutConfirmTitle &&
|
|
153
|
-
translations?.account?.logoutConfirmMessage &&
|
|
154
|
-
translations?.account?.deleteConfirmTitle &&
|
|
155
|
-
translations?.account?.deleteConfirmMessage &&
|
|
156
|
-
translations?.account?.cancel)
|
|
157
|
-
? translations.account as AccountTranslations
|
|
158
|
-
: undefined,
|
|
159
|
-
}), [user, userProfileData, handleSignIn, handleSignOut, handleDeleteAccount, translations]);
|
|
165
|
+
translations: undefined,
|
|
166
|
+
}), [handleSignIn, handleSignOut, handleDeleteAccount]);
|
|
160
167
|
|
|
161
168
|
return {
|
|
162
169
|
settingsConfig,
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Feedback Repository Interface
|
|
3
|
-
*/
|
|
4
|
-
import type { FeedbackEntity } from '../entities/FeedbackEntity';
|
|
5
|
-
export interface FeedbackError {
|
|
6
|
-
message: string;
|
|
7
|
-
code?: 'SUBMIT_FAILED' | 'FETCH_FAILED' | 'DELETE_FAILED' | 'VALIDATION_ERROR';
|
|
8
|
-
}
|
|
9
|
-
export type FeedbackResult<T> = {
|
|
10
|
-
success: true;
|
|
11
|
-
data: T;
|
|
12
|
-
} | {
|
|
13
|
-
success: false;
|
|
14
|
-
error: FeedbackError;
|
|
15
|
-
};
|
|
16
|
-
export interface IFeedbackRepository {
|
|
17
|
-
submitFeedback(feedback: FeedbackEntity | Omit<FeedbackEntity, 'id'>): Promise<FeedbackResult<FeedbackEntity>>;
|
|
18
|
-
getUserFeedback(userId: string): Promise<FeedbackResult<FeedbackEntity[]>>;
|
|
19
|
-
deleteFeedback(feedbackId: string): Promise<FeedbackResult<boolean>>;
|
|
20
|
-
}
|