UNPKG

fwk-q-firebase

Version:

Firebase access library

453 lines (431 loc) 14.2 kB
import { initializeApp } from 'firebase/app' import { getFunctions, httpsCallable } from 'firebase/functions' import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, updateProfile, GoogleAuthProvider, signInWithPopup, sendPasswordResetEmail } from 'firebase/auth' import { getFirestore, onSnapshot, collection, getDocs, doc, addDoc, deleteDoc, updateDoc, getDoc, setDoc, query, where, orderBy, writeBatch, runTransaction } from 'firebase/firestore' import { getStorage, ref, uploadBytes, uploadBytesResumable, getDownloadURL, deleteObject } from 'firebase/storage' import { getDatabase, onValue, ref as refRt } from 'firebase/database' import { Capacitor } from '@capacitor/core' import { Network } from '@capacitor/network' import { ui } from 'fwk-ui' let db let dbRt let sto let auth let rtListeners = {} let rtRefs = {} let functions const initFirebase = (cfg) => { const app = initializeApp(cfg) functions = getFunctions(app) db = getFirestore() dbRt = getDatabase(app) sto = getStorage() auth = getAuth() } const cFunction = async (fnName, payload) => { console.log('Cloud Function payload:', fnName, payload) const fn = httpsCallable(functions, fnName) const response = await fn(payload) console.log('Cloud Function response:', response) return response?.data } ///////////////////////////////////////////////////////////////////////////////////// // REALTIME DB ///////////////////////////////////////////////////////////////////////////////////// const realtimeOn = (route, proxy) => { console.log('route:', route) const lstRef = refRt(dbRt, route) rtRefs[route] = lstRef rtListeners[route] = onValue(lstRef, (snapshot) => { const data = snapshot.val() proxy.value = data }) } const realtimeOff = (route) => { //rtRefs[route].off('value', rtListeners[route]) // ("value", (snap) => {})) rtRefs[route] = null delete rtRefs[route] } //========================================================= ///////////////////////////////////////////////////////////////////////////////////// // SECURITY AUTH ///////////////////////////////////////////////////////////////////////////////////// const loginFirebase = async (email, password) => { try { const result = signInWithEmailAndPassword(auth, email, password) return result } catch (err) { console.log('signIn error:', err.message) ui.actions.notify(err.message, 'error') } } const loginGoogle = async () => { auth.useDeviceLanguage() const provider = new GoogleAuthProvider() provider.addScope('https://www.googleapis.com/auth/userinfo.email') provider.addScope('https://www.googleapis.com/auth/userinfo.profile') const redirectUrl = 'YOUR_REDIRECT_URL_HERE' auth.languageCode = 'es' try { const result = await signInWithPopup(auth, provider) return result } catch (error) { ui.actions.notify('Error Auth:', error.message) } } const logout = async () => { try { return auth.signOut() } catch (err) { console.log('logout error:', err.message) ui.actions.notify(err.message, 'error') } } const register = async (name, email, password) => { try { const { user } = await createUserWithEmailAndPassword(auth, email, password) await updateProfile(user, { displayName: name }) return user } catch (err) { console.log('registration error:', err.message) ui.actions.notify(err.message, 'error') } } const forgotPassword = (email) => { console.log('store sendResetPassword:', email) if (!email) { ui.actions.notify('Debe ingresar un mail válido!', 'warning') } else { sendPasswordResetEmail(auth, email).then(() => { ui.actions.notify('Se ha enviado el mail de blanqueo de contraseña correctamente!', 'success') }) } } const addQuote = (quote) => { if (!auth.currentUser) { return alert('Not Authorized') } return db.doc(`users/${auth.currentUser.id}`).set({ quote }) } const isInitialized = async () => { return new Promise((resolve) => { auth.onAuthStateChanged(() => { resolve(true) }) }) } const getCurrentUser = async () => { return auth.currentUser } const getCurrentUserQuote = async () => { const quote = await db .doc(`users/${auth.currentUser.uid}`) .get() return quote.get('quote') } //========================================================= ///////////////////////////////////////////////////////////////////////////////////// // CRUD ///////////////////////////////////////////////////////////////////////////////////// const getCollection = async (col) => { const colRef = collection(db, col) const colSnapshot = await getDocs(colRef) const result = colSnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id })) return result } const getCollectionQuery = async (col, multiWhere, ops) => { let q = query(collection(db, col)) multiWhere.forEach(criteria => { q = query(q, where(criteria.field, criteria.op, criteria.val)) }) if (ops?.sortField) { q = query(q, orderBy(ops.sortField, ops.sortDir)) } const querySnapshot = await getDocs(q) const result = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id })) return result } const getCollectionRefQuery = (col, multiWhere, ops) => { let q = query(collection(db, col)) multiWhere.forEach(criteria => { q = query(q, where(criteria.field, criteria.op, criteria.val)) }) if (ops?.sortField) { q = query(q, orderBy(ops.sortField, ops.sortDir)) } return q } const getCollectionFlex = async (col, ops) => { let q let operator = '==' if (ops.op) operator = ops.op if (ops.field && ops.sortField) { q = query(collection(db, col), where(ops.field, operator, ops.val), orderBy(ops.field, 'asc'), orderBy(ops.sortField, ops.sortDir)) } if (ops.field && !ops.sortField) { q = query(collection(db, col), where(ops.field, operator, ops.val)) } if (!ops.field && ops.sortField) { q = query(collection(db, col), orderBy(ops.sortField, ops.sortDir)) } if (!ops.field && !ops.sortField) { q = query(collection(db, colName)) } const querySnapshot = await getDocs(q) const result = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id })) return result } const getCollectionRef = (col) => { const colRef = collection(db, col) return colRef } const getDocument = async (col, d) => { const docRef = doc(db, col, d) const sn = await getDoc(docRef) const result = sn.data() return result } const getDocumentRef = (col, d) => { let ref if (d) { ref = doc(db, col, d) } else // new doc { ref = doc(collection(db, col)) } return ref } const addDocument = async (col, d) => { const colRef = collection(db, col) const docRef = await addDoc(colRef, d) return docRef } const setDocument = async (col, d, id, options = { merge: true }) => { let docRef removeUndefinedFields(d) if (id) { const docRef = doc(db, col, d.id || id) await setDoc(docRef, d, options) } else { const ref = collection(db, col) await addDoc(ref, d) console.log('Document has been added successfully') } return true } const emptyCollection = async (col) => { ui.actions.showLoading() const colRef = collection(db, col) const colSnapshot = await getDocs(colRef) const documents = colSnapshot.docs ui.actions.hideLoading() ui.actions.showLoading({ type: 'progressCounter', color: 'red', total: documents.length, value: 0 }) let i = 0 for (const d of documents) { await deleteDocument(col, d.id) // await sleep(5) ui.actions.setLoaderOps({ type: 'progressCounter', color: 'red', total: documents.length, value: i++ }) } ui.actions.hideLoading() } const deleteCollection = async (col, batchSize) => { const colRef = collection(db, col) const q = query(collection(db, col), orderBy('__name__')) console.log('query:', q) // const query = colRef.orderBy('__name__').limit(batchSize) // collectionRef.orderBy('__name__').limit(batchSize) return new Promise((resolve, reject) => { deleteQueryBatch(q, resolve).catch(reject) }) } const deleteDocument = async (col, id) => { const docRef = doc(db, col, id) await deleteDoc(docRef) } const batchInsert = async (col, data) => { const batch = writeBatch(db) console.log('data len: ', data.length) const filteredData = data.filter(x => !evalUndefinedFields(x)) // !!x['Fecha inicio']) console.log('data filtered len: ', filteredData.length) ui.actions.showLoading({ type: 'progressCounter', color: 'blue', total: filteredData.length, value: 0 }) let i = 1 for (const d of filteredData) { const docRef = doc(db, col, new Date().getTime()) ui.actions.setLoaderOps({ type: 'progressCounter', color: 'blue', total: filteredData.length, value: i++ }) batch.set(docRef, d) // batch.set(docRef, d) // batch.create(docRef, d) } await batch.commit() ui.actions.hideLoading() } const transaction = async (cb) => { await runTransaction(db, cb) } //========================================================= ///////////////////////////////////////////////////////////////////////////////////// // STORAGE ///////////////////////////////////////////////////////////////////////////////////// const uploadFile = async (file, fileName) => { return new Promise(async (resolve, reject) => { try { let fn = file.name if (fileName) fn = fileName const storageRef = ref(sto, fn) const uploadTask = uploadBytesResumable(storageRef, file) uploadTask.on('state_changed', (snapshot) => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100 console.log('Upload is ' + progress + '% done') switch (snapshot.state) { case 'paused': console.log('Upload is paused') break case 'running': console.log('Upload is running') break } }, (error) => { console.log('upload error:', error) switch (error.code) { case 'storage/unauthorized': ui.actions.notify('No autorizado', 'error') // User doesn't have permission to access the object break case 'storage/canceled': ui.actions.notify('Subida cancelada', 'error') break case 'storage/unknown': ui.actions.notify('Error desconocido', 'error') break } reject(error) }, async () => { const downloadURL = await getDownloadURL(uploadTask.snapshot.ref) console.log('File available at', downloadURL) resolve(downloadURL) } ) } catch (error) { console.log('Error al subir archivo:', error) reject(error) } }) } const deleteFile = async (bucket) => { await deleteObject(ref(sto, bucket)) } const getStoDownloadURL = async (bucket) => { return await getDownloadURL(ref(sto, bucket)) } //========================================================= const fb = { initFirebase, db, sto, auth, realtimeOn, realtimeOff, loginFirebase, loginGoogle, logout, register, forgotPassword, addQuote, onSnapshot, deleteObject, isInitialized, getCurrentUser, getCurrentUserQuote, getCollection, getCollectionRef, getCollectionFlex, getCollectionQuery, getCollectionRefQuery, getDocument, getDocumentRef, setDocument, addDocument, emptyCollection, deleteDocument, deleteCollection, batchInsert, transaction, uploadFile, deleteFile, getStoDownloadURL, cFunction } export default fb ///////////////////////////////////////////////////////////////////////////////////// // PRIVATE FUNCTIONS ///////////////////////////////////////////////////////////////////////////////////// async function isOnline () { const netRes = await Network.getStatus() //'wifi' | 'cellular' | 'none' | 'unknown' const status = netRes.connectionType const isOnline = (status === 'wifi' || status === 'cellular' || !status) return isOnline } async function deleteQueryBatch (query, resolve) { const snapshot = await query.get() const batchSize = snapshot.size if (batchSize === 0) { // When there are no documents left, we are done resolve() return } const batch = db.batch() snapshot.docs.forEach((doc) => { batch.delete(doc.ref) }) await batch.commit() // Recurse on the next process tick, to avoid // exploding the stack. process.nextTick(() => { deleteQueryBatch(query, resolve) }) } function removeUndefinedFields (data) { for (const key in data) { if (data[key] === undefined) { delete data[key] } } return data } function evalUndefinedFields (doc) { let flag = false for (const key in doc) { if (doc[key] === undefined) flag = true } return flag } async function sleep (tout) { return new Promise((resolve) => { setTimeout(() => { resolve() }, tout) }) }