201 lines
5.7 KiB
TypeScript
201 lines
5.7 KiB
TypeScript
/**
|
|
* Firebase Native Implementation
|
|
* Uses @react-native-firebase for Android/iOS
|
|
*/
|
|
import { Platform } from "react-native";
|
|
import auth, { FirebaseAuthTypes } from "@react-native-firebase/auth";
|
|
import firestore from "@react-native-firebase/firestore";
|
|
import messaging from "@react-native-firebase/messaging";
|
|
import functions from "@react-native-firebase/functions";
|
|
import {
|
|
GoogleSignin,
|
|
statusCodes,
|
|
} from "@react-native-google-signin/google-signin";
|
|
|
|
// Web Client ID from google-services.json
|
|
const WEB_CLIENT_ID =
|
|
"613864011564-78d915g0hm9sbveskkfcch6mrd8atktb.apps.googleusercontent.com";
|
|
|
|
// iOS Client ID from GoogleService-Info.plist
|
|
const IOS_CLIENT_ID =
|
|
"613864011564-atsg9nau8hicla4td6dedcab15g7qr04.apps.googleusercontent.com";
|
|
|
|
// Configure Google Sign-In for native
|
|
GoogleSignin.configure({
|
|
webClientId: WEB_CLIENT_ID,
|
|
iosClientId: Platform.OS === "ios" ? IOS_CLIENT_ID : undefined,
|
|
offlineAccess: true,
|
|
});
|
|
|
|
// Export types
|
|
export type { FirebaseAuthTypes };
|
|
export { statusCodes };
|
|
|
|
// Auth exports
|
|
export const firebaseAuth = auth;
|
|
export const getAuthInstance = () => auth();
|
|
export const onAuthStateChanged = (
|
|
callback: (user: FirebaseAuthTypes.User | null) => void
|
|
) => {
|
|
return auth().onAuthStateChanged(callback);
|
|
};
|
|
|
|
// Firestore exports
|
|
export const firebaseFirestore = firestore;
|
|
export const getFirestoreInstance = () => firestore();
|
|
export const FieldValue = firestore.FieldValue;
|
|
export const Timestamp = firestore.Timestamp;
|
|
|
|
// Collection helpers
|
|
export const collection = (path: string) => firestore().collection(path);
|
|
export const doc = (collectionPath: string, docId: string) =>
|
|
firestore().collection(collectionPath).doc(docId);
|
|
|
|
// Messaging exports
|
|
export const firebaseMessaging = messaging;
|
|
export const getMessagingInstance = () => messaging();
|
|
export const AuthorizationStatus = messaging.AuthorizationStatus;
|
|
|
|
// Functions exports
|
|
export const firebaseFunctions = functions;
|
|
export const getFunctionsInstance = () => functions();
|
|
export const httpsCallable = (name: string) => functions().httpsCallable(name);
|
|
|
|
// Google Sign-In (Native)
|
|
export const signInWithGoogle = async (): Promise<{
|
|
user: FirebaseAuthTypes.User | null;
|
|
isNewUser: boolean;
|
|
error?: string;
|
|
}> => {
|
|
try {
|
|
// Check if device supports Google Play Services (Android only)
|
|
if (Platform.OS === "android") {
|
|
await GoogleSignin.hasPlayServices({
|
|
showPlayServicesUpdateDialog: true,
|
|
});
|
|
}
|
|
|
|
// Sign out first to always show account picker
|
|
try {
|
|
await GoogleSignin.signOut();
|
|
} catch (e) {
|
|
// Ignore sign out errors
|
|
}
|
|
|
|
// Sign in with Google
|
|
const signInResult = await GoogleSignin.signIn();
|
|
const idToken = signInResult.data?.idToken;
|
|
|
|
if (!idToken) {
|
|
return {
|
|
user: null,
|
|
isNewUser: false,
|
|
error: "No ID token received from Google",
|
|
};
|
|
}
|
|
|
|
// Create credential and sign in to Firebase
|
|
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
|
|
const userCredential = await auth().signInWithCredential(googleCredential);
|
|
const isNewUser = userCredential.additionalUserInfo?.isNewUser ?? false;
|
|
|
|
return { user: userCredential.user, isNewUser };
|
|
} catch (error: any) {
|
|
console.error("Google Sign-In error:", error);
|
|
|
|
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
|
|
return { user: null, isNewUser: false, error: "Sign in was cancelled" };
|
|
} else if (error.code === statusCodes.IN_PROGRESS) {
|
|
return {
|
|
user: null,
|
|
isNewUser: false,
|
|
error: "Sign in is already in progress",
|
|
};
|
|
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
|
|
return {
|
|
user: null,
|
|
isNewUser: false,
|
|
error: "Google Play Services not available",
|
|
};
|
|
}
|
|
|
|
// Handle iOS-specific errors
|
|
if (Platform.OS === "ios" && error.message?.includes("simulator")) {
|
|
return {
|
|
user: null,
|
|
isNewUser: false,
|
|
error:
|
|
"Google Sign-In may not work on iOS Simulator. Please test on a real device.",
|
|
};
|
|
}
|
|
|
|
return {
|
|
user: null,
|
|
isNewUser: false,
|
|
error: error.message || "Google Sign-In failed",
|
|
};
|
|
}
|
|
};
|
|
|
|
export const signOutFromGoogle = async (): Promise<void> => {
|
|
try {
|
|
await GoogleSignin.signOut();
|
|
} catch (error) {
|
|
console.error("Google Sign-Out error:", error);
|
|
}
|
|
};
|
|
|
|
// Phone Auth (Native)
|
|
export const signInWithPhoneNumber = async (phoneNumber: string) => {
|
|
return auth().signInWithPhoneNumber(phoneNumber);
|
|
};
|
|
|
|
// Email/Password Authentication (Native)
|
|
export const createUserWithEmailAndPassword = async (
|
|
email: string,
|
|
password: string
|
|
): Promise<{ user: FirebaseAuthTypes.User | null; error?: string }> => {
|
|
try {
|
|
const userCredential = await auth().createUserWithEmailAndPassword(
|
|
email,
|
|
password
|
|
);
|
|
return { user: userCredential.user };
|
|
} catch (error: any) {
|
|
console.error('Email/Password signup error:', error);
|
|
return {
|
|
user: null,
|
|
error: error.message || 'Failed to create account',
|
|
};
|
|
}
|
|
};
|
|
|
|
export const signInWithEmailAndPassword = async (
|
|
email: string,
|
|
password: string
|
|
): Promise<{ user: FirebaseAuthTypes.User | null; error?: string }> => {
|
|
try {
|
|
const userCredential = await auth().signInWithEmailAndPassword(
|
|
email,
|
|
password
|
|
);
|
|
return { user: userCredential.user };
|
|
} catch (error: any) {
|
|
console.error('Email/Password signin error:', error);
|
|
return {
|
|
user: null,
|
|
error: error.message || 'Failed to sign in',
|
|
};
|
|
}
|
|
};
|
|
|
|
// Firebase Auth sign out
|
|
export const signOut = async (): Promise<void> => {
|
|
await signOutFromGoogle();
|
|
await auth().signOut();
|
|
};
|
|
|
|
// Platform identifier
|
|
export const isNative = true;
|
|
export const isWeb = false;
|