Based also on Udemy course Build an app with React, Redux and Firestore from scratch by Neil Cummings
npm i -g firebase-tools firebase logout firebase login firebase init Choose by space Functions: Configure and deploy Cloud Functions Press Enter
cd myProject firebase deploy --only functions
Based on video #213 in the course
REACT_APP_API_KEY=AIzb.... REACT_APP_MAPS_KEY=AIzc....
process.env.REACT_APP_API_KEY
<script src="https://maps.googleapis.com/maps/api/js?key=%REACT_APP_MAPS_KEY%&libraries=places">
npm run build
puts production flag during the process.
"scripts": { "start": "react-scripts start", "build": "react-scripts build", ... "deploy": "npm run build && firebase deploy" },
firebase init
* Unique ID (uid) * Email address * Name * PhotoURLFirebase cannot add additional properties to the User object directly such as (user's description or Bio or resources). To save those properties Firestore should be used (in addition to the copy of user object from firebase authentication).
// db.collection(USERS_COLLECTION).doc(userUid).collection(PHOTOS_COLLECTION);
export const addEventToFirestore = (event) => { const user = firebase.auth().currentUser; return db.collection(EVENTS_COLLECTION).add({ ...event, hostUid: user.uid, hostedBy: user.displayName, hostPhotoURL: user.photoURL || null, attendees: firebase.firestore.FieldValue.arrayUnion({ id: user.uid, displayName: user.displayName, photoURL: user.photoURL || null, }), attendeesIds: firebase.firestore.FieldValue.arrayUnion( user.uid ) }); }
export const getUserEventsQuery = (activeTab, userUid) => { const eventsRef = db.collection(EVENTS_COLLECTION); const today = new Date(); switch (activeTab) { case 1: // past return eventsRef.where("attendeesIds", "array-contains", userUid).where("date", "<=", today).orderBy("date", "desc"); // most recent event first case 2: // hosting return eventsRef.where("hostUid", "==", userUid).orderBy("date", "desc"); // most recent event first default: // future return eventsRef.where("attendeesIds", "array-contains", userUid).where("date", ">", today).orderBy("date"); } };
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if request.time < timestamp.date(2021, 4, 19); } } }
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow create: if isSignedIn(); allow read, update, delete: if request.auth.uid == userId } } } function isSignedIn() { return request.auth.uid !=null }
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /cars/{docId} { allow read: if existingData().myField == true; <--- important: add in the code db.collection("cars").where('myField', '==', true) <--- important: creation of the index in firestore db is required. Follow the error message in the console allow create, write, update, delete: if isSignedIn() } } } function existingData() { return resource.data; } function isSignedIn() { return request.auth.uid !=null }
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read: if isSignedIn(); allow update, create: if request.auth.uid == userId match /photos/{document=**} { allow read: if isSignedIn(); allow write: if request.auth.uid == userId } } match /following/{userId}/{document=**} { allow read: if isSignedIn(); allow write: if request.auth.uid == userId allow update: if resource.id == request.auth.uid; } match /events/{document=**} { allow read, list; allow create: if isSignedIn(); allow update: if isHost(); allow update: if isSignedIn() && updateAttendeeFieldsOnly(); } } } function isSignedIn() { return request.auth.uid !=null } function isHost() { return isSignedIn() && resource.data.hostUid == request.auth.uid; } function updateAttendeeFieldsOnly() { return incomingData().diff(existingData()).changedKeys().hasOnly(['attendeesIds', 'attendees']) } function existingData() { return resource.data; } function incomingData() { return request.resource.data; }
User can read another user's doc if it's authenticated
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { <--- userId is a parameter allow read: if request.auth.uid !=null <--- user can read another user's document if they are authenticated } } }
User can read another user's doc if it's authenticated
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read: if request.auth.uid !=null allow update, create: if request.auth.uid == userId match /photos/{document=**} { <--- photos sub-collection inside users collection under specific user allow read: if request.auth.uid !=null allow write: if request.auth.uid == userId <--- write is for creation, update and deletion } } } }
User can read another user's doc if it's authenticated
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read: if request.auth.uid !=null allow update, create: if request.auth.uid == userId match /photos/{document=**} { allow read: if request.auth.uid !=null allow write: if request.auth.uid == userId } } match /following/{userId}/{document=**} { allow read: if request.auth.uid !=null allow write: if request.auth.uid == userId } match /events/{document=**} { allow read, list; allow write: if request.auth.uid !=null } } }
... allow update: if request.resource.data... <--- incoming data that is sent
... allow update: if resource.data... <--- existing data
import firebase from "app/config/firebase"; const db = firebase.firestore(); export const followUser = async (profile) => { const user = firebase.auth().currentUser; const batch = db.batch(); try { batch.set(db.collection(FOLLOWING_COLLECTION).doc(user.uid).collection(USER_FOLLOWING).doc(profile.id), { displayName: profile.displayName, photoURL: profile.photoURL, uid: profile.id, }); batch.set(db.collection(FOLLOWING_COLLECTION).doc(profile.id).collection(USER_FOLLOWERS).doc(user.uid), { displayName: user.displayName, photoURL: user.photoURL, uid: user.uid, }); batch.update(db.collection(USERS_COLLECTION).doc(user.uid), { followingCount: firebase.firestore.FieldValue.increment(1), }); batch.update(db.collection(USERS_COLLECTION).doc(profile.id), { followerCount: firebase.firestore.FieldValue.increment(1), }); return await batch.commit() } catch (error) { console.log(error); throw error; } };
export const unfollowUser = async (profile) => { const user = firebase.auth().currentUser; const batch = db.batch(); try { batch.delete(db.collection(FOLLOWING_COLLECTION).doc(user.uid).collection(USER_FOLLOWING).doc(profile.id)); batch.delete(db.collection(FOLLOWING_COLLECTION).doc(profile.id).collection(USER_FOLLOWERS).doc(user.uid)); batch.update(db.collection(USERS_COLLECTION).doc(user.uid), { followingCount: firebase.firestore.FieldValue.increment(-1), }); batch.update(db.collection(USERS_COLLECTION).doc(profile.id), { followerCount: firebase.firestore.FieldValue.increment(-1), }); return await batch.commit(); } catch (error) { console.log(error); throw error; } };
export const unfollowUser = async (profile) => { const user = firebase.auth().currentUser; try { await db.collection(FOLLOWING_COLLECTION).doc(user.uid).collection(USER_FOLLOWING).doc(profile.id).delete(); await db.collection(FOLLOWING_COLLECTION).doc(profile.id).collection(USER_FOLLOWERS).doc(user.uid).delete(); await db .collection(USERS_COLLECTION) .doc(user.uid) .update({ followingCount: firebase.firestore.FieldValue.increment(-1), }); return await db .collection(USERS_COLLECTION) .doc(profile.id) .update({ followerCount: firebase.firestore.FieldValue.increment(-1), }); } catch (error) { console.log(error); throw error; } };
npm i firebase
config/firebase.js
file:
import firebase from "firebase/app"; import 'firebase/firestore'; import 'firebase/database'; // for cheat import "firebase/auth"; import "firebase/storage"; // for photographs const firebaseConfig = { apiKey: "AIzXYZ", authDomain: "rev-XYZ.firebaseapp.com", projectId: "rev-XYZ", storageBucket: "rev-XYZ.appspot.com", messagingSenderId: "13JJJ", appId: "1:13ABC", }; firebase.initializeApp(firebaseConfig); firebase.firestore(); export default firebase;
Continue to console
button.firestore/firestoreService.js
file:
import firebase from 'config/firebase'; const db = firebase.firestore(); export function getEventsFromFireStore(observer) { return db.collection("events").onSnapshot(observer); // quick way to be sure that things are connected }