@umituz/react-native-auth 3.6.61 → 3.6.63

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 (40) hide show
  1. package/package.json +5 -5
  2. package/src/application/ports/IAuthRepository.ts +3 -3
  3. package/src/index.ts +5 -18
  4. package/src/infrastructure/providers/FirebaseAuthProvider.ts +6 -2
  5. package/src/infrastructure/repositories/AuthRepository.ts +3 -3
  6. package/src/infrastructure/services/AuthEventService.ts +4 -0
  7. package/src/infrastructure/services/AuthService.ts +14 -36
  8. package/src/infrastructure/services/initializeAuth.ts +0 -15
  9. package/src/infrastructure/utils/AuthValidation.ts +5 -2
  10. package/src/infrastructure/utils/UserMapper.ts +9 -6
  11. package/src/infrastructure/utils/authStateHandler.ts +0 -7
  12. package/src/infrastructure/utils/validation/sanitization.ts +2 -89
  13. package/src/init/createAuthInitModule.ts +0 -15
  14. package/src/presentation/hooks/mutations/useAuthMutations.ts +3 -3
  15. package/src/presentation/hooks/useAuthBottomSheet.ts +10 -1
  16. package/src/presentation/hooks/useGoogleAuth.ts +43 -11
  17. package/src/presentation/stores/auth.selectors.ts +12 -6
  18. package/src/presentation/stores/authStore.ts +6 -9
  19. package/src/presentation/stores/initializeAuthListener.ts +44 -7
  20. package/src/application/ports/IAuthService.ts +0 -60
  21. package/src/domain/utils/migration.ts +0 -44
  22. package/src/infrastructure/adapters/UIProviderAdapter.ts +0 -43
  23. package/src/infrastructure/services/UserDocument.types.ts +0 -60
  24. package/src/infrastructure/services/UserDocumentService.ts +0 -86
  25. package/src/infrastructure/services/app-service-helpers.ts +0 -35
  26. package/src/infrastructure/types/UI.types.ts +0 -11
  27. package/src/infrastructure/utils/auth-tracker.util.ts +0 -23
  28. package/src/infrastructure/utils/userDocumentBuilder.util.ts +0 -114
  29. package/src/infrastructure/utils/validation/BaseValidators.ts +0 -35
  30. package/src/infrastructure/utils/validation/CollectionValidators.ts +0 -56
  31. package/src/infrastructure/utils/validation/DateValidators.ts +0 -71
  32. package/src/infrastructure/utils/validation/FormValidators.ts +0 -22
  33. package/src/infrastructure/utils/validation/NumberValidators.ts +0 -50
  34. package/src/infrastructure/utils/validation/StringValidators.ts +0 -55
  35. package/src/infrastructure/utils/validation/types.ts +0 -15
  36. package/src/presentation/screens/change-password/ChangePasswordScreen.tsx +0 -179
  37. package/src/presentation/screens/change-password/ChangePasswordScreen.types.ts +0 -77
  38. package/src/presentation/screens/change-password/RequirementItem.tsx +0 -47
  39. package/src/presentation/screens/change-password/index.ts +0 -6
  40. package/src/types/translations.types.ts +0 -89
@@ -29,21 +29,33 @@ export interface UseGoogleAuthResult {
29
29
  signInWithGoogle: () => Promise<SocialAuthResult>;
30
30
  googleLoading: boolean;
31
31
  googleConfigured: boolean;
32
+ googleError: string | null;
32
33
  }
33
34
 
34
35
  const PLACEHOLDER_CLIENT_ID = "000000000000-placeholder.apps.googleusercontent.com";
35
36
 
37
+ /**
38
+ * Validate Google auth config
39
+ */
40
+ function validateGoogleConfig(config?: GoogleAuthConfig): boolean {
41
+ if (!config) return false;
42
+
43
+ const hasValidClientId =
44
+ !!(config.iosClientId && config.iosClientId !== PLACEHOLDER_CLIENT_ID) ||
45
+ !!(config.webClientId && config.webClientId !== PLACEHOLDER_CLIENT_ID) ||
46
+ !!(config.androidClientId && config.androidClientId !== PLACEHOLDER_CLIENT_ID);
47
+
48
+ return hasValidClientId;
49
+ }
50
+
36
51
  /**
37
52
  * Hook for Google authentication with expo-auth-session
38
53
  */
39
54
  export function useGoogleAuth(config?: GoogleAuthConfig): UseGoogleAuthResult {
40
55
  const [isLoading, setIsLoading] = useState(false);
56
+ const [googleError, setGoogleError] = useState<string | null>(null);
41
57
 
42
- const googleConfigured = !!(
43
- config?.iosClientId ||
44
- config?.webClientId ||
45
- config?.androidClientId
46
- );
58
+ const googleConfigured = validateGoogleConfig(config);
47
59
 
48
60
  const socialAuthConfig: SocialAuthConfig = {
49
61
  google: config,
@@ -70,8 +82,11 @@ export function useGoogleAuth(config?: GoogleAuthConfig): UseGoogleAuthResult {
70
82
  const idToken = googleResponse.authentication?.idToken;
71
83
  if (idToken) {
72
84
  setIsLoading(true);
85
+ setGoogleError(null);
73
86
  signInWithGoogleToken(idToken)
74
87
  .catch((error) => {
88
+ const errorMessage = error instanceof Error ? error.message : "Firebase sign-in failed";
89
+ setGoogleError(errorMessage);
75
90
  if (__DEV__) {
76
91
  console.error("[useGoogleAuth] Firebase sign-in failed:", error);
77
92
  }
@@ -80,23 +95,33 @@ export function useGoogleAuth(config?: GoogleAuthConfig): UseGoogleAuthResult {
80
95
  setIsLoading(false);
81
96
  });
82
97
  }
98
+ } else if (googleResponse?.type === "error") {
99
+ setGoogleError("Google authentication failed");
100
+ setIsLoading(false);
83
101
  }
84
102
  }, [googleResponse, signInWithGoogleToken]);
85
103
 
86
104
  const signInWithGoogle = useCallback(async (): Promise<SocialAuthResult> => {
87
105
  if (!promptGoogleAsync) {
88
- return { success: false, error: "expo-auth-session is not available" };
106
+ const error = "expo-auth-session is not available";
107
+ setGoogleError(error);
108
+ return { success: false, error };
89
109
  }
90
110
 
91
111
  if (!googleConfigured) {
92
- return { success: false, error: "Google Sign-In is not configured" };
112
+ const error = "Google Sign-In is not configured. Please provide valid client IDs.";
113
+ setGoogleError(error);
114
+ return { success: false, error };
93
115
  }
94
116
 
95
117
  if (!request) {
96
- return { success: false, error: "Google Sign-In not ready" };
118
+ const error = "Google Sign-In not ready";
119
+ setGoogleError(error);
120
+ return { success: false, error };
97
121
  }
98
122
 
99
123
  setIsLoading(true);
124
+ setGoogleError(null);
100
125
  try {
101
126
  const result = await promptGoogleAsync();
102
127
 
@@ -108,14 +133,20 @@ export function useGoogleAuth(config?: GoogleAuthConfig): UseGoogleAuthResult {
108
133
  }
109
134
 
110
135
  if (result.type === "cancel") {
111
- return { success: false, error: "Google Sign-In was cancelled" };
136
+ const error = "Google Sign-In was cancelled";
137
+ setGoogleError(error);
138
+ return { success: false, error };
112
139
  }
113
140
 
114
- return { success: false, error: "Google Sign-In failed" };
141
+ const error = "Google Sign-In failed";
142
+ setGoogleError(error);
143
+ return { success: false, error };
115
144
  } catch (error) {
145
+ const errorMessage = error instanceof Error ? error.message : "Google sign-in failed";
146
+ setGoogleError(errorMessage);
116
147
  return {
117
148
  success: false,
118
- error: error instanceof Error ? error.message : "Google sign-in failed",
149
+ error: errorMessage,
119
150
  };
120
151
  } finally {
121
152
  setIsLoading(false);
@@ -126,5 +157,6 @@ export function useGoogleAuth(config?: GoogleAuthConfig): UseGoogleAuthResult {
126
157
  signInWithGoogle,
127
158
  googleLoading: isLoading || firebaseLoading,
128
159
  googleConfigured,
160
+ googleError,
129
161
  };
130
162
  }
@@ -71,34 +71,40 @@ export const selectShowAuthModal = (state: { showAuthModal: (callback?: () => vo
71
71
 
72
72
  /**
73
73
  * Get current user ID
74
+ * Uses firebaseUser as single source of truth
74
75
  */
75
76
  export const selectUserId = (state: AuthStore): string | null => {
76
- return state.firebaseUser?.uid ?? state.user?.uid ?? null;
77
+ return state.firebaseUser?.uid ?? null;
77
78
  };
78
79
 
79
80
  /**
80
- * Check if user is authenticated (not anonymous)
81
+ * Check if user is authenticated (has a valid Firebase user, not anonymous)
82
+ * Uses firebaseUser as single source of truth
81
83
  */
82
84
  export const selectIsAuthenticated = (state: AuthStore): boolean => {
83
- return !!state.user && !state.isAnonymous && !state.user.isAnonymous;
85
+ const hasFirebaseUser = !!state.firebaseUser;
86
+ const isNotAnonymous = !state.firebaseUser?.isAnonymous;
87
+ return hasFirebaseUser && isNotAnonymous;
84
88
  };
85
89
 
86
90
  /**
87
91
  * Check if user is anonymous
92
+ * Uses firebaseUser as single source of truth
88
93
  */
89
94
  export const selectIsAnonymous = (state: AuthStore): boolean => {
90
- return state.firebaseUser?.isAnonymous ?? state.user?.isAnonymous ?? false;
95
+ return state.firebaseUser?.isAnonymous ?? false;
91
96
  };
92
97
 
93
98
  /**
94
99
  * Get current user type
100
+ * Derived from firebaseUser state
95
101
  */
96
102
  export const selectUserType = (state: AuthStore): UserType => {
97
- if (!state.firebaseUser && !state.user) {
103
+ if (!state.firebaseUser) {
98
104
  return "none";
99
105
  }
100
106
 
101
- return selectIsAnonymous(state) ? "anonymous" : "authenticated";
107
+ return state.firebaseUser.isAnonymous ? "anonymous" : "authenticated";
102
108
  };
103
109
 
104
110
  /**
@@ -71,17 +71,14 @@ export const useAuthStore = createStore<AuthState, AuthActions>({
71
71
  },
72
72
 
73
73
  setIsAnonymous: (isAnonymous) => {
74
- const { user } = get();
74
+ const { firebaseUser } = get();
75
75
  if (__DEV__) {
76
- console.log("[AuthStore] setIsAnonymous:", { isAnonymous, hadUser: !!user });
77
- }
78
- // Update user.isAnonymous flag to match the new state
79
- // This handles both anonymous → registered and registered → anonymous conversions
80
- if (user && user.isAnonymous !== isAnonymous) {
81
- set({ isAnonymous, user: { ...user, isAnonymous } });
82
- } else {
83
- set({ isAnonymous });
76
+ console.log("[AuthStore] setIsAnonymous:", { isAnonymous, hasFirebaseUser: !!firebaseUser });
84
77
  }
78
+ // Only update the isAnonymous flag
79
+ // The user object will be updated by setFirebaseUser when needed
80
+ // This prevents inconsistencies between firebaseUser and user
81
+ set({ isAnonymous });
85
82
  },
86
83
 
87
84
  setError: (error) => {
@@ -20,6 +20,8 @@ const ANONYMOUS_SIGNIN_TIMEOUT_MS = 10000;
20
20
  let listenerInitialized = false;
21
21
  let listenerRefCount = 0;
22
22
  let firebaseUnsubscribe: (() => void) | null = null;
23
+ let anonymousSignInInProgress = false; // Prevent race conditions
24
+ let initializationInProgress = false; // Prevent duplicate initialization
23
25
 
24
26
  /**
25
27
  * Initialize Firebase auth listener
@@ -34,9 +36,20 @@ export function initializeAuthListener(
34
36
  console.log("[AuthListener] initializeAuthListener called:", {
35
37
  autoAnonymousSignIn,
36
38
  alreadyInitialized: listenerInitialized,
39
+ initializationInProgress,
37
40
  });
38
41
  }
39
42
 
43
+ // Prevent duplicate initialization - return existing unsubscribe if already initializing
44
+ if (initializationInProgress) {
45
+ if (__DEV__) {
46
+ console.warn("[AuthListener] Initialization already in progress, returning existing unsubscribe");
47
+ }
48
+ return () => {
49
+ // No-op - will be handled by the initial initialization
50
+ };
51
+ }
52
+
40
53
  // If already initialized, increment ref count and return unsubscribe that decrements
41
54
  if (listenerInitialized) {
42
55
  listenerRefCount++;
@@ -58,10 +71,14 @@ export function initializeAuthListener(
58
71
  firebaseUnsubscribe = null;
59
72
  listenerInitialized = false;
60
73
  listenerRefCount = 0;
74
+ anonymousSignInInProgress = false;
61
75
  }
62
76
  };
63
77
  }
64
78
 
79
+ // Mark initialization as in progress
80
+ initializationInProgress = true;
81
+
65
82
  const auth = getFirebaseAuth();
66
83
  const store = useAuthStore.getState();
67
84
 
@@ -69,6 +86,7 @@ export function initializeAuthListener(
69
86
  if (__DEV__) {
70
87
  console.log("[AuthListener] No Firebase auth, marking initialized");
71
88
  }
89
+ initializationInProgress = false;
72
90
  store.setLoading(false);
73
91
  store.setInitialized(true);
74
92
  return () => {};
@@ -103,21 +121,31 @@ export function initializeAuthListener(
103
121
  }
104
122
 
105
123
  if (!user && autoAnonymousSignIn) {
124
+ // Prevent race condition: only one anonymous sign-in at a time
125
+ if (anonymousSignInInProgress) {
126
+ if (__DEV__) {
127
+ console.log("[AuthListener] Anonymous sign-in already in progress, skipping");
128
+ }
129
+ store.setFirebaseUser(null);
130
+ return;
131
+ }
132
+
106
133
  if (__DEV__) {
107
134
  console.log("[AuthListener] No user, auto signing in anonymously...");
108
135
  }
109
136
  // Set loading state while attempting sign-in
110
137
  store.setLoading(true);
138
+ anonymousSignInInProgress = true;
111
139
 
112
- // Start anonymous sign-in process
113
- // Don't return early - let the listener continue to handle state changes
140
+ // Start anonymous sign-in without blocking the listener
141
+ // The listener will be triggered again when sign-in completes
114
142
  void (async () => {
115
- // Add timeout protection
116
- const timeoutPromise = new Promise((_, reject) =>
117
- setTimeout(() => reject(new Error("Anonymous sign-in timeout")), ANONYMOUS_SIGNIN_TIMEOUT_MS)
118
- );
119
-
120
143
  try {
144
+ // Add timeout protection
145
+ const timeoutPromise = new Promise((_, reject) =>
146
+ setTimeout(() => reject(new Error("Anonymous sign-in timeout")), ANONYMOUS_SIGNIN_TIMEOUT_MS)
147
+ );
148
+
121
149
  // Race between sign-in and timeout
122
150
  await Promise.race([
123
151
  (async () => {
@@ -156,6 +184,8 @@ export function initializeAuthListener(
156
184
  store.setLoading(false);
157
185
  store.setInitialized(true);
158
186
  store.setError("Failed to sign in anonymously. Please check your connection.");
187
+ } finally {
188
+ anonymousSignInInProgress = false;
159
189
  }
160
190
  })();
161
191
 
@@ -163,6 +193,7 @@ export function initializeAuthListener(
163
193
  // The listener will be triggered again when sign-in succeeds
164
194
  // For now, set null user and let loading state indicate in-progress
165
195
  store.setFirebaseUser(null);
196
+ initializationInProgress = false;
166
197
  return;
167
198
  }
168
199
 
@@ -179,6 +210,8 @@ export function initializeAuthListener(
179
210
  onAuthStateChange?.(user);
180
211
  });
181
212
 
213
+ initializationInProgress = false;
214
+
182
215
  return () => {
183
216
  listenerRefCount--;
184
217
  if (__DEV__) {
@@ -193,6 +226,8 @@ export function initializeAuthListener(
193
226
  firebaseUnsubscribe = null;
194
227
  listenerInitialized = false;
195
228
  listenerRefCount = 0;
229
+ anonymousSignInInProgress = false;
230
+ initializationInProgress = false;
196
231
  }
197
232
  };
198
233
  }
@@ -207,6 +242,8 @@ export function resetAuthListener(): void {
207
242
  }
208
243
  listenerInitialized = false;
209
244
  listenerRefCount = 0;
245
+ anonymousSignInInProgress = false;
246
+ initializationInProgress = false;
210
247
  }
211
248
 
212
249
  /**
@@ -1,60 +0,0 @@
1
- /**
2
- * Auth Service Interface
3
- * Port for authentication operations (provider-agnostic)
4
- */
5
-
6
- import type { AuthUser } from "../../domain/entities/AuthUser";
7
-
8
- export interface SignUpParams {
9
- email: string;
10
- password: string;
11
- displayName?: string;
12
- }
13
-
14
- export interface SignInParams {
15
- email: string;
16
- password: string;
17
- }
18
-
19
- export interface IAuthService {
20
- /**
21
- * Sign up a new user
22
- */
23
- signUp(params: SignUpParams): Promise<AuthUser>;
24
-
25
- /**
26
- * Sign in an existing user
27
- */
28
- signIn(params: SignInParams): Promise<AuthUser>;
29
-
30
- /**
31
- * Sign out current user
32
- */
33
- signOut(): Promise<void>;
34
-
35
- /**
36
- * Set anonymous mode (no authentication)
37
- */
38
- setAnonymousMode(): Promise<void>;
39
-
40
- /**
41
- * Check if currently in anonymous mode
42
- */
43
- getIsAnonymousMode(): boolean;
44
-
45
- /**
46
- * Get current authenticated user
47
- */
48
- getCurrentUser(): AuthUser | null;
49
-
50
- /**
51
- * Subscribe to auth state changes
52
- */
53
- onAuthStateChange(callback: (user: AuthUser | null) => void): () => void;
54
-
55
- /**
56
- * Check if auth is initialized
57
- */
58
- isInitialized(): boolean;
59
- }
60
-
@@ -1,44 +0,0 @@
1
- /**
2
- * User Data Migration Utilities
3
- * Handles migrating data when anonymous user converts to authenticated user
4
- */
5
-
6
- export interface MigrationConfig {
7
- onMigrationStart?: (anonymousId: string, authId: string) => void;
8
- onMigrationComplete?: (anonymousId: string, authId: string) => void;
9
- onMigrationError?: (error: Error) => void;
10
- }
11
-
12
- let migrationConfig: MigrationConfig = {};
13
-
14
- export const configureMigration = (config: MigrationConfig): void => {
15
- migrationConfig = config;
16
- };
17
-
18
- export const migrateUserData = (
19
- anonymousId: string,
20
- authId: string
21
- ): void => {
22
- if (__DEV__) {
23
- console.log(`[Migration] Starting migration from ${anonymousId} to ${authId}`);
24
- }
25
-
26
- try {
27
- migrationConfig.onMigrationStart?.(anonymousId, authId);
28
-
29
- // App-specific migration logic handled via callbacks
30
- // This keeps the package generic and flexible
31
-
32
- migrationConfig.onMigrationComplete?.(anonymousId, authId);
33
-
34
- if (__DEV__) {
35
- console.log(`[Migration] Successfully migrated data for ${authId}`);
36
- }
37
- } catch (error) {
38
- if (__DEV__) {
39
- console.error(`[Migration] Failed to migrate user data:`, error);
40
- }
41
- migrationConfig.onMigrationError?.(error as Error);
42
- // Silent fail - don't block auth flow
43
- }
44
- };
@@ -1,43 +0,0 @@
1
- /**
2
- * UI Provider Adapter
3
- * Adapts external UI implementations to our IUIProvider interface
4
- */
5
-
6
- import type { DesignTokens } from "@umituz/react-native-design-system";
7
- import type { IUIProvider } from "../types/UI.types";
8
-
9
- export class UIProviderAdapter implements IUIProvider {
10
- private theme: DesignTokens | null = null;
11
- private localization: Record<string, unknown> | null = null;
12
-
13
- constructor(theme?: DesignTokens, localization?: Record<string, unknown>) {
14
- this.theme = theme || null;
15
- this.localization = localization || null;
16
- }
17
-
18
- getTheme(): DesignTokens | null {
19
- return this.theme;
20
- }
21
-
22
- getLocalization(): Record<string, unknown> | null {
23
- return this.localization;
24
- }
25
-
26
- updateTheme(theme: DesignTokens): void {
27
- this.theme = theme;
28
- }
29
-
30
- updateLocalization(localization: Record<string, unknown>): void {
31
- this.localization = localization;
32
- }
33
- }
34
-
35
- /**
36
- * Create UI provider from theme and localization implementations
37
- */
38
- export function createUIProvider(
39
- theme?: DesignTokens,
40
- localization?: Record<string, unknown>
41
- ): IUIProvider {
42
- return new UIProviderAdapter(theme, localization);
43
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * User Document Types and Configuration
3
- */
4
-
5
- /**
6
- * Minimal user interface for document creation
7
- * Compatible with both Firebase User and AuthUser
8
- */
9
- export interface UserDocumentUser {
10
- uid: string;
11
- displayName?: string | null;
12
- email?: string | null;
13
- photoURL?: string | null;
14
- isAnonymous?: boolean;
15
- }
16
-
17
- /**
18
- * Configuration for user document service
19
- */
20
- export interface UserDocumentConfig {
21
- /** Firestore collection name (default: "users") */
22
- collectionName?: string;
23
- /** Additional fields to store with user document */
24
- extraFields?: Record<string, unknown>;
25
- /** Callback to collect device/app info */
26
- collectExtras?: () => Promise<UserDocumentExtras>;
27
- }
28
-
29
- /**
30
- * User document extras from device/app
31
- */
32
- export interface UserDocumentExtras {
33
- [key: string]: string | number | boolean | null | undefined;
34
- deviceId?: string;
35
- persistentDeviceId?: string;
36
- nativeDeviceId?: string;
37
- platform?: string;
38
- deviceModel?: string;
39
- deviceBrand?: string;
40
- deviceName?: string;
41
- deviceType?: number | string;
42
- deviceYearClass?: number | string;
43
- isDevice?: boolean;
44
- osName?: string;
45
- osVersion?: string;
46
- osBuildId?: string;
47
- totalMemory?: number | string;
48
- appVersion?: string;
49
- buildNumber?: string;
50
- locale?: string;
51
- region?: string;
52
- timezone?: string;
53
- screenWidth?: number;
54
- screenHeight?: number;
55
- screenScale?: number;
56
- fontScale?: number;
57
- isLandscape?: boolean;
58
- previousAnonymousUserId?: string;
59
- signUpMethod?: string;
60
- }
@@ -1,86 +0,0 @@
1
- /**
2
- * User Document Service
3
- * Generic service for creating/updating user documents in Firestore
4
- */
5
-
6
- import { doc, getDoc, setDoc, serverTimestamp } from "firebase/firestore";
7
- import type { User } from "firebase/auth";
8
- import { getFirestore } from "@umituz/react-native-firebase";
9
- import type {
10
- UserDocumentUser,
11
- UserDocumentConfig,
12
- UserDocumentExtras,
13
- } from "./UserDocument.types";
14
- import {
15
- getSignUpMethod,
16
- buildBaseData,
17
- buildCreateData,
18
- buildUpdateData,
19
- } from "../utils/userDocumentBuilder.util";
20
-
21
- export type {
22
- UserDocumentUser,
23
- UserDocumentConfig,
24
- UserDocumentExtras,
25
- } from "./UserDocument.types";
26
-
27
- let userDocumentConfig: UserDocumentConfig = {};
28
-
29
- export function configureUserDocumentService(config: UserDocumentConfig): void {
30
- userDocumentConfig = { ...config };
31
- }
32
-
33
- export async function ensureUserDocument(
34
- user: UserDocumentUser | User,
35
- extras?: UserDocumentExtras,
36
- ): Promise<boolean> {
37
- const db = getFirestore();
38
- if (!db || !user.uid || user.uid.trim().length === 0) return false;
39
-
40
- try {
41
- let allExtras = extras || {};
42
- if (userDocumentConfig.collectExtras) {
43
- const collectedExtras = await userDocumentConfig.collectExtras();
44
- allExtras = { ...collectedExtras, ...allExtras };
45
- }
46
-
47
- if (!allExtras.signUpMethod) allExtras.signUpMethod = getSignUpMethod(user);
48
-
49
- const collectionName = userDocumentConfig.collectionName || "users";
50
- const userRef = doc(db, collectionName, user.uid);
51
- const userDoc = await getDoc(userRef);
52
- const baseData = buildBaseData(user, allExtras);
53
-
54
- const docData = !userDoc.exists()
55
- ? buildCreateData(baseData, userDocumentConfig.extraFields, allExtras)
56
- : buildUpdateData(baseData, allExtras);
57
-
58
- await setDoc(userRef, docData, { merge: true });
59
- return true;
60
- } catch (error) {
61
- if (__DEV__) {
62
- console.error("[UserDocumentService] Failed:", error);
63
- }
64
- return false;
65
- }
66
- }
67
-
68
- export async function markUserDeleted(userId: string): Promise<boolean> {
69
- const db = getFirestore();
70
- if (!db || !userId) return false;
71
-
72
- try {
73
- const userRef = doc(db, userDocumentConfig.collectionName || "users", userId);
74
- await setDoc(userRef, {
75
- isDeleted: true,
76
- deletedAt: serverTimestamp(),
77
- updatedAt: serverTimestamp(),
78
- }, { merge: true });
79
- return true;
80
- } catch (error) {
81
- if (__DEV__) {
82
- console.error("[UserDocumentService] markUserDeleted failed:", error);
83
- }
84
- return false;
85
- }
86
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * App Service Helpers
3
- * Creates ready-to-use auth service for configureAppServices
4
- */
5
-
6
- import { useAuthStore } from "../../presentation/stores/authStore";
7
- import { selectIsAuthenticated, selectUserId } from "../../presentation/stores/auth.selectors";
8
- import { useAuthModalStore } from "../../presentation/stores/authModalStore";
9
-
10
- export interface IAppAuthServiceHelper {
11
- getUserId: () => string | null;
12
- isAuthenticated: () => boolean;
13
- requireAuth: () => string;
14
- }
15
-
16
- /**
17
- * Creates an auth service implementation for configureAppServices
18
- */
19
- export function createAuthService(): IAppAuthServiceHelper {
20
- return {
21
- getUserId: () => selectUserId(useAuthStore.getState()),
22
- isAuthenticated: () => selectIsAuthenticated(useAuthStore.getState()),
23
- requireAuth: () => {
24
- if (!selectIsAuthenticated(useAuthStore.getState())) {
25
- useAuthModalStore.getState().showAuthModal();
26
- throw new Error("Auth required");
27
- }
28
- const userId = selectUserId(useAuthStore.getState());
29
- if (!userId) {
30
- throw new Error("User ID missing");
31
- }
32
- return userId;
33
- },
34
- };
35
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * UI Provider Interface
3
- * Generic interface for theme and localization providers
4
- */
5
-
6
- import type { DesignTokens } from "@umituz/react-native-design-system";
7
-
8
- export interface IUIProvider {
9
- getTheme(): DesignTokens | null;
10
- getLocalization(): Record<string, unknown> | null;
11
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * Simple tracker for auth operations
3
- */
4
-
5
- export const authTracker = {
6
- logOperationStarted: (operation: string, data?: Record<string, unknown>) => {
7
- if (__DEV__) {
8
- console.log(`[Auth] ${operation} started`, data);
9
- }
10
- },
11
-
12
- logOperationSuccess: (operation: string, data?: Record<string, unknown>) => {
13
- if (__DEV__) {
14
- console.log(`[Auth] ${operation} successful`, data);
15
- }
16
- },
17
-
18
- logOperationError: (operation: string, error: unknown, metadata?: Record<string, unknown>) => {
19
- if (__DEV__) {
20
- console.error(`[Auth] ${operation} failed`, { error, ...metadata });
21
- }
22
- }
23
- };