@umituz/react-native-firebase 2.4.58 → 2.4.60

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-firebase",
3
- "version": "2.4.58",
3
+ "version": "2.4.60",
4
4
  "description": "Unified Firebase package for React Native apps - Auth and Firestore services using Firebase JS SDK (no native modules).",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -3,7 +3,7 @@
3
3
  * Builds user document data for Firestore (max 100 lines)
4
4
  */
5
5
 
6
- import { serverTimestamp } from "firebase/firestore";
6
+ import { serverTimestamp, increment } from "firebase/firestore";
7
7
  import type {
8
8
  UserDocumentUser,
9
9
  UserDocumentExtras,
@@ -82,6 +82,7 @@ export function buildCreateData(
82
82
  createdAt: serverTimestamp(),
83
83
  updatedAt: serverTimestamp(),
84
84
  lastLoginAt: serverTimestamp(),
85
+ loginCount: 1,
85
86
  };
86
87
 
87
88
  if (extras?.previousAnonymousUserId) {
@@ -106,6 +107,7 @@ export function buildUpdateData(
106
107
  ...baseData,
107
108
  lastLoginAt: serverTimestamp(),
108
109
  updatedAt: serverTimestamp(),
110
+ loginCount: increment(1),
109
111
  };
110
112
 
111
113
  if (extras?.previousAnonymousUserId) {
@@ -117,3 +119,33 @@ export function buildUpdateData(
117
119
 
118
120
  return updateData;
119
121
  }
122
+
123
+ /**
124
+ * Builds a login history entry for the loginHistory subcollection
125
+ */
126
+ export function buildLoginHistoryEntry(
127
+ user: UserDocumentUser,
128
+ extras?: UserDocumentExtras,
129
+ ): Record<string, unknown> {
130
+ return {
131
+ loginAt: serverTimestamp(),
132
+ provider: getSignUpMethod(user) ?? "unknown",
133
+ email: user.email ?? null,
134
+ displayName: user.displayName ?? null,
135
+ isAnonymous: user.isAnonymous ?? false,
136
+ platform: extras?.platform ?? null,
137
+ deviceModel: extras?.deviceModel ?? null,
138
+ deviceBrand: extras?.deviceBrand ?? null,
139
+ osName: extras?.osName ?? null,
140
+ osVersion: extras?.osVersion ?? null,
141
+ appVersion: extras?.appVersion ?? null,
142
+ buildNumber: extras?.buildNumber ?? null,
143
+ locale: extras?.locale ?? null,
144
+ region: extras?.region ?? null,
145
+ timezone: extras?.timezone ?? null,
146
+ screenWidth: extras?.screenWidth ?? null,
147
+ screenHeight: extras?.screenHeight ?? null,
148
+ deviceId: extras?.persistentDeviceId ?? extras?.deviceId ?? null,
149
+ isConversion: !!extras?.previousAnonymousUserId,
150
+ };
151
+ }
@@ -3,7 +3,7 @@
3
3
  * Generic service for creating/updating user documents in Firestore
4
4
  */
5
5
 
6
- import { doc, getDoc, setDoc, serverTimestamp } from "firebase/firestore";
6
+ import { doc, getDoc, setDoc, addDoc, collection, serverTimestamp } from "firebase/firestore";
7
7
  import type { User } from "firebase/auth";
8
8
  import { getFirestore } from "../../../firestore";
9
9
  import type {
@@ -16,6 +16,7 @@ import {
16
16
  buildBaseData,
17
17
  buildCreateData,
18
18
  buildUpdateData,
19
+ buildLoginHistoryEntry,
19
20
  } from "./user-document-builder.util";
20
21
 
21
22
  declare const __DEV__: boolean;
@@ -52,6 +53,16 @@ export async function ensureUserDocument(
52
53
  : buildUpdateData(baseData, allExtras);
53
54
 
54
55
  await setDoc(userRef, docData, { merge: true });
56
+
57
+ // Write login history entry (fire-and-forget)
58
+ const historyEntry = buildLoginHistoryEntry(user, allExtras);
59
+ const historyRef = collection(db, collectionName, user.uid, "loginHistory");
60
+ addDoc(historyRef, historyEntry).catch((err) => {
61
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
62
+ console.warn("[UserDocumentService] Failed to write login history:", err);
63
+ }
64
+ });
65
+
55
66
  return true;
56
67
  } catch (error) {
57
68
  if (typeof __DEV__ !== "undefined" && __DEV__) {
@@ -4,7 +4,7 @@
4
4
  * This hook is optional and requires expo-auth-session to be installed
5
5
  */
6
6
 
7
- import { useState, useCallback, useEffect } from "react";
7
+ import { useState, useCallback, useEffect, useRef } from "react";
8
8
  import { googleOAuthService } from "../../infrastructure/services/google-oauth.service";
9
9
  import { getFirebaseAuth } from "../../infrastructure/config/FirebaseAuthClient";
10
10
  import type { GoogleOAuthConfig } from "../../infrastructure/services/google-oauth.service";
@@ -61,6 +61,10 @@ export function useGoogleOAuth(config?: GoogleOAuthConfig): UseGoogleOAuthResult
61
61
  const googleAvailable = googleOAuthService.isAvailable();
62
62
  const googleConfigured = googleOAuthService.isConfigured(config);
63
63
 
64
+ // Keep config in a ref so the response useEffect doesn't re-run when config object reference changes
65
+ const configRef = useRef(config);
66
+ configRef.current = config;
67
+
64
68
  // Call the Hook directly (only valid in React component)
65
69
  // If expo-auth-session is not available, these will be null
66
70
  const [request, response, promptAsync] = isExpoAuthAvailable && ExpoAuthSession
@@ -90,7 +94,7 @@ export function useGoogleOAuth(config?: GoogleOAuthConfig): UseGoogleOAuthResult
90
94
 
91
95
  await googleOAuthService.signInWithOAuth(
92
96
  auth,
93
- config,
97
+ configRef.current,
94
98
  async () => response
95
99
  );
96
100
  } catch (error) {
@@ -107,7 +111,7 @@ export function useGoogleOAuth(config?: GoogleOAuthConfig): UseGoogleOAuthResult
107
111
  };
108
112
 
109
113
  handleResponse();
110
- }, [response, googleAvailable, config]);
114
+ }, [response, googleAvailable]); // config read via ref to prevent re-running on reference changes
111
115
 
112
116
  const signInWithGoogle = useCallback(async (): Promise<SocialAuthResult> => {
113
117
  if (!googleAvailable) {