@fanam-pkg/core-utils
Version:
Core Functions are managed here for quick web development
408 lines (357 loc) • 13.3 kB
text/typescript
import {useRef} from "react"
import firebase from "firebase/compat/app"
import "firebase/compat/auth"
import "firebase/compat/firestore"
import "firebase/compat/messaging"
import {useCommon} from "../hooks"
export type DocumentData = firebase.firestore.DocumentData
export type DocumentSnapshot = firebase.firestore.DocumentSnapshot
export type QueryDocumentSnapshot = firebase.firestore.QueryDocumentSnapshot
export type QuerySnapshot = firebase.firestore.QuerySnapshot
export type CollectionRef = firebase.firestore.CollectionReference
export type DocumentRef = firebase.firestore.DocumentReference
export type SetOptions = firebase.firestore.SetOptions
export const useFirebase = (
onVerified?: (user: firebase.auth.UserCredential, authToken: string) => void,
onFailed?: (data?: string) => void
) => {
const {isDocumentReady} = useCommon()
const recaptchaVerifier = useRef<firebase.auth.RecaptchaVerifier>()
const confirmationResult = useRef<firebase.auth.ConfirmationResult>()
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
}
const app = !firebase.apps.length ? firebase.initializeApp(firebaseConfig) : firebase.app()
const auth = firebase.auth(app)
const fireStore = firebase.firestore(app)
let messaging: firebase.messaging.Messaging | null = null
if (isDocumentReady()) messaging = firebase.messaging(app)
const googleProvider = new firebase.auth.GoogleAuthProvider()
const facebookProvider = new firebase.auth.FacebookAuthProvider()
facebookProvider.addScope("email")
/* Phone number Authentication */
const onSignInSuccess = async (response: firebase.auth.UserCredential) => {
recaptchaVerifier.current?.clear()
const authToken = await response.user?.getIdToken()
if (onVerified) onVerified(response, authToken || "")
}
/* Send OTP to the phone number */
const sendOtp = (
countryCode: string,
mobile: string,
onOtpSent: () => void,
onFailed?: () => void
) => {
// Only initialize if it hasn't been initialized
if (!recaptchaVerifier.current) {
recaptchaVerifier.current = new firebase.auth.RecaptchaVerifier("auth-proceed-button", {
size: "invisible",
})
}
// Make sure the reCAPTCHA is cleared (optional)
// recaptchaVerifier.current.clear() // Only if you want to reset manually
auth
.signInWithPhoneNumber(countryCode + mobile, recaptchaVerifier.current)
.then(response => {
confirmationResult.current = response
console.log("OTP Sent Successfully >>>>>>>>>>>>>>")
onOtpSent()
})
.catch(reason => {
console.error("FIREBASE ERROR While sending OTP >>>>>>>>>>>>>>", reason)
if (onFailed) onFailed()
})
}
/* Verify the sent OTP to the phone number */
const verifyOTP = (otp: string) => {
if (confirmationResult.current) {
confirmationResult.current
.confirm(otp)
.then(onSignInSuccess)
.catch(reason => {
console.error("FIREBASE ERROR OTP Verification error >>>>>>>>>>>>>>", reason)
if (onFailed) onFailed("Invalid OTP Please try again")
})
}
}
const getAuthToken = async (): Promise<string> => (await auth?.currentUser?.getIdToken()) || ""
/* Google Provider Sign-in */
const googleSignInPopup = async () => {
try {
const response = await auth.signInWithPopup(googleProvider)
if (response) onSignInSuccess(response)
} catch (error) {
console.error("Firebase Google AuthToken googleSignInDesktop >>>>>>>>>>>", error)
if (onFailed) onFailed()
}
}
const googleSignInRedirect = () => {
//To sign in by redirecting to the sign-in page
auth.signInWithRedirect(googleProvider)
}
const googleSignInCallback = async () => {
try {
const response = await auth.getRedirectResult()
if (response) onSignInSuccess(response)
} catch (error) {
console.error("Caught error in googleSignInRedirectResult >>>>>>>>>>>", error)
if (onFailed) onFailed()
}
}
/* Verifying user email and password */
const verifyEmailPassword = (email: string, password: string) => {
auth
.signInWithEmailAndPassword(email, password)
.then(onSignInSuccess)
.catch(reason => {
console.error("FIREBASE ERROR WHILE SIGNING IN >>>>>>>>>>>>>>", reason)
if (onFailed) onFailed(reason?.message)
})
}
/* new user Sign up with email password */
const signupEmailPassword = (email: string, password: string) => {
auth
.createUserWithEmailAndPassword(email, password)
.then(onSignInSuccess)
.catch(reason => {
console.error("FIREBASE CREATING EMAIL LOGIN >>>>>>>>>>>>>>", reason)
if (onFailed) onFailed(reason?.message)
})
}
/* sending login link to the user email */
const sendEmailVerificationLink = async (
email: string,
redirectUrl: string,
onSuccess: () => void,
onFailure: (value: string) => void
) => {
try {
await auth.sendSignInLinkToEmail(email, {
url: `${redirectUrl}?email=${email}`,
handleCodeInApp: true,
})
onSuccess()
} catch (error) {
onFailure((error as Record<string, string>)["message"])
}
}
/*signing in using email link verification*/
const verifyEmailLogin = (email: string, url: string) => {
auth
.signInWithEmailLink(email, url)
.then(onSignInSuccess)
.catch(error => {
if (onFailed) onFailed(error?.message)
})
}
/*email link verification*/
const isEmailSigninLink = (url: string) => auth.isSignInWithEmailLink(url)
/*facebook login method*/
const facebookSignInPopup = async () => {
try {
const response = await auth.signInWithPopup(facebookProvider)
if (response) onSignInSuccess(response)
} catch (error) {
console.error("Firebase Facebook AuthToken facebookSignInDesktop >>>>>>>>>>>", error)
if (onFailed) onFailed()
}
}
const facebookSignInRedirect = () => {
//To sign in by redirecting to the sign-in page
auth.signInWithRedirect(facebookProvider)
}
/*facebook sign in call back method*/
const facebookSignInCallback = async () => {
try {
const response = await auth.getRedirectResult()
if (response) onSignInSuccess(response)
} catch (error) {
console.error("Caught error in facebookSignInRedirectResult >>>>>>>>>>>", error)
if (onFailed) onFailed()
}
}
const getSWRegistration = async () => {
let registration: ServiceWorkerRegistration | undefined = undefined
try {
if ("serviceWorker" in navigator) {
const registrations = await navigator.serviceWorker.getRegistrations()
registration = registrations.find(
worker => worker.active && worker.active.scriptURL && worker.active.scriptURL.includes("service-worker.js")
)
}
} catch (error) {
console.error(">>>>>>>>>>>>>> Caught Error while registering service-worker.js: ", error)
}
return registration
}
const getFCMToken = async () => {
let fcmToken: null | string = null
try {
const registration = await getSWRegistration()
if (messaging && registration) {
fcmToken = await messaging.getToken({
serviceWorkerRegistration: registration,
vapidKey: process.env.NEXT_PUBLIC_FIREBASE_VAPID_KEY,
})
console.log(">>>>>>>>>>>>>>>: FCM Token Fetched successfully")
}
} catch (error) {
console.error("Caught error in FCM TOKEN >>>>>>>>>>>: ", error)
}
return fcmToken
}
const getCollectionRef = (collections: string[]) => {
const noOfCollection = collections.length
let collectionRef: CollectionRef | DocumentRef = fireStore.collection(collections[0])
switch (noOfCollection) {
case 2:
collectionRef = collectionRef.doc(collections[1])
break
case 3:
collectionRef = collectionRef.doc(collections[1]).collection(collections[2])
break
case 4:
collectionRef = collectionRef.doc(collections[1]).collection(collections[2]).doc(collections[3])
break
case 5:
collectionRef = collectionRef
.doc(collections[1])
.collection(collections[2])
.doc(collections[3])
.collection(collections[4])
break
case 6:
collectionRef = collectionRef
.doc(collections[1])
.collection(collections[2])
.doc(collections[3])
.collection(collections[4])
.doc(collections[5])
break
case 7:
collectionRef = collectionRef
.doc(collections[1])
.collection(collections[2])
.doc(collections[3])
.collection(collections[4])
.doc(collections[5])
.collection(collections[6])
break
case 8:
collectionRef = collectionRef
.doc(collections[1])
.collection(collections[2])
.doc(collections[3])
.collection(collections[4])
.doc(collections[5])
.collection(collections[6])
.doc(collections[7])
break
case 9:
collectionRef = collectionRef
.doc(collections[1])
.collection(collections[2])
.doc(collections[3])
.collection(collections[4])
.doc(collections[5])
.collection(collections[6])
.doc(collections[7])
.collection(collections[8])
break
default:
break
}
return collectionRef
}
const addData = async <D>(collections: string[], data: D, options: SetOptions = {merge: true, mergeFields: []}) => {
let response: D | null = null
try {
const {mergeFields, merge} = options
const option = mergeFields?.length ? {mergeFields} : {merge}
if (collections.length % 2 === 0)
await (getCollectionRef(collections) as DocumentRef).set(data as Partial<DocumentData>, option)
else await (getCollectionRef(collections) as CollectionRef).add(data as Partial<DocumentData>)
response = data
} catch (error) {
console.error("ERROR While Adding data to firestore: >>>>>>>>>>>>>>>>", error)
}
return response
}
const updateData = async <D>(collections: string[], data: D) => {
let response: D | null = null
try {
await (getCollectionRef(collections) as DocumentRef).update(data as Partial<DocumentData>)
response = data
} catch (error) {
console.error("ERROR While Adding data to firestore: >>>>>>>>>>>>>>>>", error)
}
return response
}
const getCollection = async <R>(collections: string[] | string) => {
let data: R[] = []
try {
const response = await (
getCollectionRef(typeof collections === "string" ? [collections] : collections) as CollectionRef
).get()
data = response.docs.map(item => item.data() as R)
} catch (error) {
console.error("ERROR While fetching firestore collections: >>>>>>>>>>>>>>>>", error)
}
return data
}
const getData = async <R>(collections: string[] | string) => {
let data: R | null = null
try {
const response = await (
getCollectionRef(typeof collections === "string" ? [collections] : collections) as DocumentRef
).get()
data = response.data() as R
} catch (error) {
console.error("ERROR While fetching firestore collections: >>>>>>>>>>>>>>>>", error)
}
return data
}
const deleteData = async (collections: string[] | string) => {
let isSuccess: boolean = false
try {
await (getCollectionRef(typeof collections === "string" ? [collections] : collections) as DocumentRef).delete()
isSuccess = true
} catch (error) {
console.error("ERROR While fetching firestore collections: >>>>>>>>>>>>>>>>", error)
}
return isSuccess
}
const onSignOut = async () => await auth.signOut()
return {
verifyOTP,
sendOtp,
getAuthToken,
onSignOut,
messaging,
fireStore,
getData,
updateData,
getCollection,
addData,
deleteData,
googleSignInPopup,
googleSignInRedirect,
googleSignInCallback,
verifyEmailPassword,
signupEmailPassword,
sendEmailVerificationLink,
verifyEmailLogin,
isEmailSigninLink,
facebookSignInPopup,
facebookSignInRedirect,
facebookSignInCallback,
getFCMToken,
firebaseConfig,
}
}