├── .gitignore ├── 1-Firebase-Getting-Started ├── end │ ├── .firebaserc │ ├── .gitignore │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── FirebaseConfig.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── start │ ├── empty.txt │ └── yarn.lock ├── 2-Firebase-Hosting ├── end │ ├── .firebaserc │ ├── .github │ │ └── workflows │ │ │ ├── firebase-hosting-merge.yml │ │ │ └── firebase-hosting-pull-request.yml │ ├── .gitignore │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── FirebaseConfig.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── start │ ├── .firebaserc │ ├── .gitignore │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── FirebaseConfig.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js │ └── yarn.lock ├── 3-Firebase-Authentication ├── end │ ├── .firebaserc │ ├── .github │ │ └── workflows │ │ │ ├── firebase-hosting-merge.yml │ │ │ └── firebase-hosting-pull-request.yml │ ├── .gitignore │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── FirebaseAuthService.js │ │ ├── FirebaseConfig.js │ │ ├── components │ │ │ └── LoginForm.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── start │ ├── .firebaserc │ ├── .github │ └── workflows │ │ ├── firebase-hosting-merge.yml │ │ └── firebase-hosting-pull-request.yml │ ├── .gitignore │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── FirebaseConfig.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js │ └── yarn.lock ├── 4-Firebase-Firestore ├── end │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── FirebaseAuthService.js │ │ ├── FirebaseConfig.js │ │ ├── FirebaseFirestoreService.js │ │ ├── components │ │ │ ├── AddEditRecipeForm.js │ │ │ └── LoginForm.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── start │ ├── .firebaserc │ ├── .github │ └── workflows │ │ ├── firebase-hosting-merge.yml │ │ └── firebase-hosting-pull-request.yml │ ├── .gitignore │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── FirebaseAuthService.js │ ├── FirebaseConfig.js │ ├── components │ │ └── LoginForm.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js │ └── yarn.lock ├── 5-Firebase-Storage ├── end │ ├── .firebaserc │ ├── .github │ │ └── workflows │ │ │ ├── firebase-hosting-merge.yml │ │ │ └── firebase-hosting-pull-request.yml │ ├── .gitignore │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── FirebaseAuthService.js │ │ ├── FirebaseConfig.js │ │ ├── FirebaseFirestoreService.js │ │ ├── FirebaseStorageService.js │ │ ├── components │ │ │ ├── AddEditRecipeForm.js │ │ │ ├── ImageUploadPreview.js │ │ │ └── LoginForm.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── start │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── FirebaseAuthService.js │ ├── FirebaseConfig.js │ ├── FirebaseFirestoreService.js │ ├── components │ │ ├── AddEditRecipeForm.js │ │ └── LoginForm.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js │ └── yarn.lock ├── 6-Firebase-Functions ├── end │ ├── .firebaserc │ ├── README.md │ ├── firebase.json │ ├── functions │ │ ├── .gitignore │ │ ├── FirebaseConfig.js │ │ ├── index.js │ │ ├── package.json │ │ ├── recipesApi.js │ │ ├── utilities.js │ │ └── yarn.lock │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── FirebaseAuthService.js │ │ ├── FirebaseConfig.js │ │ ├── FirebaseFirestoreRestService.js │ │ ├── FirebaseFirestoreService.js │ │ ├── FirebaseStorageService.js │ │ ├── components │ │ │ ├── AddEditRecipeForm.js │ │ │ ├── ImageUploadPreview.js │ │ │ └── LoginForm.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── start │ ├── README.md │ ├── firebase.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── FirebaseAuthService.js │ ├── FirebaseConfig.js │ ├── FirebaseFirestoreService.js │ ├── FirebaseStorageService.js │ ├── components │ │ ├── AddEditRecipeForm.js │ │ ├── ImageUploadPreview.js │ │ └── LoginForm.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js │ └── yarn.lock ├── 7-Firebase-Web-NPM-JavaScript-SDK-Version-9 ├── end │ ├── README.md │ ├── firebase.json │ ├── functions │ │ ├── .gitignore │ │ ├── FirebaseConfig.js │ │ ├── index.js │ │ ├── package.json │ │ ├── recipesApi.js │ │ ├── utilities.js │ │ └── yarn.lock │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── FirebaseAuthService.js │ │ ├── FirebaseConfig.js │ │ ├── FirebaseFirestoreRestService.js │ │ ├── FirebaseFirestoreService.js │ │ ├── FirebaseStorageService.js │ │ ├── components │ │ │ ├── AddEditRecipeForm.js │ │ │ ├── ImageUploadPreview.js │ │ │ └── LoginForm.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ ├── reportWebVitals.js │ │ └── setupTests.js │ └── yarn.lock └── start │ ├── README.md │ ├── firebase.json │ ├── functions │ ├── .gitignore │ ├── FirebaseConfig.js │ ├── index.js │ ├── package.json │ ├── recipesApi.js │ ├── utilities.js │ └── yarn.lock │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── FirebaseAuthService.js │ ├── FirebaseConfig.js │ ├── FirebaseFirestoreRestService.js │ ├── FirebaseFirestoreService.js │ ├── FirebaseStorageService.js │ ├── components │ │ ├── AddEditRecipeForm.js │ │ ├── ImageUploadPreview.js │ │ └── LoginForm.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reportWebVitals.js │ └── setupTests.js │ └── yarn.lock ├── App.css └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # production 12 | build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | fir-recipes-3d91c-firebase-adminsdk-wyvwz-d53a1193f0.json 26 | 27 | *.log 28 | 29 | .env 30 | 31 | .firebase 32 | 33 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/1-Firebase-Getting-Started/end/README.md -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": [ 23 | "react-app", 24 | "react-app/jest" 25 | ] 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/1-Firebase-Getting-Started/end/public/favicon.ico -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/1-Firebase-Getting-Started/end/public/logo192.png -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/1-Firebase-Getting-Started/end/public/logo512.png -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | 3 | import firebase from './FirebaseConfig'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 |

Firebase Recipes

10 |
11 |
12 | ); 13 | } 14 | 15 | export default App; 16 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/end/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/start/empty.txt: -------------------------------------------------------------------------------- 1 | Start Section 1 on Udemy to get started -------------------------------------------------------------------------------- /1-Firebase-Getting-Started/start/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | "on": 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: npm install 15 | - run: npm run build 16 | - uses: FirebaseExtended/action-hosting-deploy@v0 17 | with: 18 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 19 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 20 | channelId: live 21 | projectId: fir-recipes-15644 22 | env: 23 | FIREBASE_CLI_PREVIEWS: hostingchannels 24 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | "on": pull_request 6 | jobs: 7 | build_and_preview: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - run: npm install 12 | - run: npm run build 13 | - uses: FirebaseExtended/action-hosting-deploy@v0 14 | with: 15 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 16 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 17 | projectId: fir-recipes-15644 18 | env: 19 | FIREBASE_CLI_PREVIEWS: hostingchannels 20 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/README.md: -------------------------------------------------------------------------------- 1 | This Section Added the `.env` file for our web app. 2 | 3 | It'll look something like this but with your firebase web app project info 4 | 5 | REACT_APP_API_KEY="asd-asd" 6 | REACT_APP_AUTH_DOMAIN="asd-qwe-zxc.firebaseapp.com" 7 | REACT_APP_PROJECT_ID="asd-qwe-qwe" 8 | REACT_APP_STORAGE_BUCKET="fir-qwe-qwe.qwe.com" 9 | REACT_APP_MESSAGING_SENDER_ID="ewqqweqwe" 10 | REACT_APP_APP_ID="1:eqweqwe:web:qweqweqwe" 11 | REACT_APP_MEASUREMENT_ID="G-qeweqweqwe" 12 | 13 | You should have also run `firebase init` inside of your project which generates the .firebasesrc file and firebase.json file. -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject", 20 | "buildDeploy": "yarn build && firebase deploy --only hosting" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/2-Firebase-Hosting/end/public/favicon.ico -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/2-Firebase-Hosting/end/public/logo192.png -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/2-Firebase-Hosting/end/public/logo512.png -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | 3 | // eslint-disable-next-line no-unused-vars 4 | import firebase from './FirebaseConfig'; 5 | 6 | function App() { 7 | return ( 8 |
9 |
10 |

Firebase Recipes

11 |
12 |
13 | ); 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/end/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/2-Firebase-Hosting/start/README.md -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": [ 23 | "react-app", 24 | "react-app/jest" 25 | ] 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/2-Firebase-Hosting/start/public/favicon.ico -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/2-Firebase-Hosting/start/public/logo192.png -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/2-Firebase-Hosting/start/public/logo512.png -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | 3 | import firebase from './FirebaseConfig'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 |

Firebase Recipes

10 |
11 |
12 | ); 13 | } 14 | 15 | export default App; 16 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /2-Firebase-Hosting/start/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | "on": 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | env: 13 | REACT_APP_API_KEY: "${{ secrets.REACT_APP_API_KEY }}" 14 | REACT_APP_AUTH_DOMAIN: "${{ secrets.REACT_APP_AUTH_DOMAIN }}" 15 | REACT_APP_DATABASE_URL: "${{ secrets.REACT_APP_DATABASE_URL }}" 16 | REACT_APP_PROJECT_ID: "${{ secrets.REACT_APP_PROJECT_ID }}" 17 | REACT_APP_STORAGE_BUCKET: "${{ secrets.REACT_APP_STORAGE_BUCKET }}" 18 | REACT_APP_MESSAGING_SENDER_ID: "${{ secrets.REACT_APP_MESSAGING_SENDER_ID }}" 19 | REACT_APP_APP_ID: "${{ secrets.REACT_APP_APP_ID }}" 20 | REACT_APP_MEASUREMENT_ID: "${{ secrets.REACT_APP_MEASUREMENT_ID }}" 21 | steps: 22 | - uses: actions/checkout@v2 23 | - run: npm install 24 | - run: npm run build 25 | - uses: FirebaseExtended/action-hosting-deploy@v0 26 | with: 27 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 28 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 29 | channelId: live 30 | projectId: fir-recipes-15644 31 | env: 32 | FIREBASE_CLI_PREVIEWS: hostingchannels 33 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | "on": pull_request 6 | jobs: 7 | build_and_preview: 8 | runs-on: ubuntu-latest 9 | env: 10 | REACT_APP_API_KEY: "${{ secrets.REACT_APP_API_KEY }}" 11 | REACT_APP_AUTH_DOMAIN: "${{ secrets.REACT_APP_AUTH_DOMAIN }}" 12 | REACT_APP_DATABASE_URL: "${{ secrets.REACT_APP_DATABASE_URL }}" 13 | REACT_APP_PROJECT_ID: "${{ secrets.REACT_APP_PROJECT_ID }}" 14 | REACT_APP_STORAGE_BUCKET: "${{ secrets.REACT_APP_STORAGE_BUCKET }}" 15 | REACT_APP_MESSAGING_SENDER_ID: "${{ secrets.REACT_APP_MESSAGING_SENDER_ID }}" 16 | REACT_APP_APP_ID: "${{ secrets.REACT_APP_APP_ID }}" 17 | REACT_APP_MEASUREMENT_ID: "${{ secrets.REACT_APP_MEASUREMENT_ID }}" 18 | steps: 19 | - uses: actions/checkout@v2 20 | - run: npm install 21 | - run: npm run build 22 | - uses: FirebaseExtended/action-hosting-deploy@v0 23 | with: 24 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 25 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 26 | projectId: fir-recipes-15644 27 | env: 28 | FIREBASE_CLI_PREVIEWS: hostingchannels 29 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject", 20 | "buildDeploy": "yarn build && firebase deploy --only hosting" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/3-Firebase-Authentication/end/public/favicon.ico -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/3-Firebase-Authentication/end/public/logo192.png -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/3-Firebase-Authentication/end/public/logo512.png -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/App.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import FirebaseAuthService from './FirebaseAuthService'; 3 | import LoginForm from './components/LoginForm'; 4 | 5 | import './App.css'; 6 | 7 | function App() { 8 | const [user, setUser] = useState(null); 9 | 10 | FirebaseAuthService.subscribeToAuthChanges(setUser); 11 | 12 | return ( 13 |
14 |
15 |

Firebase Recipes

16 | 17 |
18 |
19 | ); 20 | } 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | loginUser, 35 | logoutUser, 36 | sendPasswordResetEmail, 37 | loginWithGoogle, 38 | subscribeToAuthChanges, 39 | }; 40 | 41 | export default FirebaseAuthService; 42 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/end/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | "on": 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - run: npm install 15 | - run: npm run build 16 | - uses: FirebaseExtended/action-hosting-deploy@v0 17 | with: 18 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 19 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 20 | channelId: live 21 | projectId: fir-recipes-15644 22 | env: 23 | FIREBASE_CLI_PREVIEWS: hostingchannels 24 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | "on": pull_request 6 | jobs: 7 | build_and_preview: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - run: npm install 12 | - run: npm run build 13 | - uses: FirebaseExtended/action-hosting-deploy@v0 14 | with: 15 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 16 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 17 | projectId: fir-recipes-15644 18 | env: 19 | FIREBASE_CLI_PREVIEWS: hostingchannels 20 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject", 20 | "buildDeploy": "yarn build && firebase deploy --only hosting" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/3-Firebase-Authentication/start/public/favicon.ico -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/3-Firebase-Authentication/start/public/logo192.png -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/3-Firebase-Authentication/start/public/logo512.png -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | 3 | // eslint-disable-next-line no-unused-vars 4 | import firebase from './FirebaseConfig'; 5 | 6 | function App() { 7 | return ( 8 |
9 |
10 |

Firebase Recipes

11 |
12 |
13 | ); 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /3-Firebase-Authentication/start/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject", 20 | "buildDeploy": "yarn build && firebase deploy --only hosting" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/4-Firebase-Firestore/end/public/favicon.ico -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/4-Firebase-Firestore/end/public/logo192.png -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/4-Firebase-Firestore/end/public/logo512.png -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | registerUser, 35 | loginUser, 36 | logoutUser, 37 | sendPasswordResetEmail, 38 | loginWithGoogle, 39 | subscribeToAuthChanges, 40 | }; 41 | 42 | export default FirebaseAuthService; 43 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/FirebaseFirestoreService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const firestore = firebase.firestore(); 4 | 5 | const createDocument = (collection, document) => { 6 | return firestore.collection(collection).add(document); 7 | }; 8 | 9 | const readDocument = (collection, id) => { 10 | return firestore.collection(collection).doc(id).get(); 11 | }; 12 | 13 | const readDocuments = async ({ 14 | collection, 15 | queries, 16 | orderByField, 17 | orderByDirection, 18 | perPage, 19 | cursorId, 20 | }) => { 21 | let collectionRef = firestore.collection(collection); 22 | 23 | if (queries && queries.length > 0) { 24 | for (const query of queries) { 25 | collectionRef = collectionRef.where( 26 | query.field, 27 | query.condition, 28 | query.value 29 | ); 30 | } 31 | } 32 | 33 | if (orderByField && orderByDirection) { 34 | collectionRef = collectionRef.orderBy(orderByField, orderByDirection); 35 | } 36 | 37 | if (perPage) { 38 | collectionRef = collectionRef.limit(perPage); 39 | } 40 | 41 | if (cursorId) { 42 | const document = await readDocument(collection, cursorId); 43 | 44 | collectionRef = collectionRef.startAfter(document); 45 | } 46 | 47 | return collectionRef.get(); 48 | }; 49 | 50 | const updateDocument = (collection, id, document) => { 51 | return firestore.collection(collection).doc(id).update(document); 52 | }; 53 | 54 | const deleteDocument = (collection, id) => { 55 | return firestore.collection(collection).doc(id).delete(); 56 | }; 57 | 58 | const FirebaseFirestoreService = { 59 | createDocument, 60 | readDocuments, 61 | updateDocument, 62 | deleteDocument, 63 | }; 64 | 65 | export default FirebaseFirestoreService; 66 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/end/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | "on": 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | env: 13 | REACT_APP_API_KEY: "${{ secrets.REACT_APP_API_KEY }}" 14 | REACT_APP_AUTH_DOMAIN: "${{ secrets.REACT_APP_AUTH_DOMAIN }}" 15 | REACT_APP_DATABASE_URL: "${{ secrets.REACT_APP_DATABASE_URL }}" 16 | REACT_APP_PROJECT_ID: "${{ secrets.REACT_APP_PROJECT_ID }}" 17 | REACT_APP_STORAGE_BUCKET: "${{ secrets.REACT_APP_STORAGE_BUCKET }}" 18 | REACT_APP_MESSAGING_SENDER_ID: "${{ secrets.REACT_APP_MESSAGING_SENDER_ID }}" 19 | REACT_APP_APP_ID: "${{ secrets.REACT_APP_APP_ID }}" 20 | REACT_APP_MEASUREMENT_ID: "${{ secrets.REACT_APP_MEASUREMENT_ID }}" 21 | steps: 22 | - uses: actions/checkout@v2 23 | - run: npm install 24 | - run: npm run build 25 | - uses: FirebaseExtended/action-hosting-deploy@v0 26 | with: 27 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 28 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 29 | channelId: live 30 | projectId: fir-recipes-15644 31 | env: 32 | FIREBASE_CLI_PREVIEWS: hostingchannels 33 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | "on": pull_request 6 | jobs: 7 | build_and_preview: 8 | runs-on: ubuntu-latest 9 | env: 10 | REACT_APP_API_KEY: "${{ secrets.REACT_APP_API_KEY }}" 11 | REACT_APP_AUTH_DOMAIN: "${{ secrets.REACT_APP_AUTH_DOMAIN }}" 12 | REACT_APP_DATABASE_URL: "${{ secrets.REACT_APP_DATABASE_URL }}" 13 | REACT_APP_PROJECT_ID: "${{ secrets.REACT_APP_PROJECT_ID }}" 14 | REACT_APP_STORAGE_BUCKET: "${{ secrets.REACT_APP_STORAGE_BUCKET }}" 15 | REACT_APP_MESSAGING_SENDER_ID: "${{ secrets.REACT_APP_MESSAGING_SENDER_ID }}" 16 | REACT_APP_APP_ID: "${{ secrets.REACT_APP_APP_ID }}" 17 | REACT_APP_MEASUREMENT_ID: "${{ secrets.REACT_APP_MEASUREMENT_ID }}" 18 | steps: 19 | - uses: actions/checkout@v2 20 | - run: npm install 21 | - run: npm run build 22 | - uses: FirebaseExtended/action-hosting-deploy@v0 23 | with: 24 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 25 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 26 | projectId: fir-recipes-15644 27 | env: 28 | FIREBASE_CLI_PREVIEWS: hostingchannels 29 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject", 20 | "buildDeploy": "yarn build && firebase deploy --only hosting" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/4-Firebase-Firestore/start/public/favicon.ico -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/4-Firebase-Firestore/start/public/logo192.png -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/4-Firebase-Firestore/start/public/logo512.png -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/App.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import FirebaseAuthService from './FirebaseAuthService'; 3 | import LoginForm from './components/LoginForm'; 4 | 5 | import './App.css'; 6 | 7 | function App() { 8 | const [user, setUser] = useState(null); 9 | 10 | FirebaseAuthService.subscribeToAuthChanges(setUser); 11 | 12 | return ( 13 |
14 |
15 |

Firebase Recipes

16 | 17 |
18 |
19 | ); 20 | } 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | loginUser, 35 | logoutUser, 36 | sendPasswordResetEmail, 37 | loginWithGoogle, 38 | subscribeToAuthChanges, 39 | }; 40 | 41 | export default FirebaseAuthService; 42 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /4-Firebase-Firestore/start/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | "on": 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | env: 13 | REACT_APP_API_KEY: "${{ secrets.REACT_APP_API_KEY }}" 14 | REACT_APP_AUTH_DOMAIN: "${{ secrets.REACT_APP_AUTH_DOMAIN }}" 15 | REACT_APP_DATABASE_URL: "${{ secrets.REACT_APP_DATABASE_URL }}" 16 | REACT_APP_PROJECT_ID: "${{ secrets.REACT_APP_PROJECT_ID }}" 17 | REACT_APP_STORAGE_BUCKET: "${{ secrets.REACT_APP_STORAGE_BUCKET }}" 18 | REACT_APP_MESSAGING_SENDER_ID: "${{ secrets.REACT_APP_MESSAGING_SENDER_ID }}" 19 | REACT_APP_APP_ID: "${{ secrets.REACT_APP_APP_ID }}" 20 | REACT_APP_MEASUREMENT_ID: "${{ secrets.REACT_APP_MEASUREMENT_ID }}" 21 | steps: 22 | - uses: actions/checkout@v2 23 | - run: npm install 24 | - run: npm run build 25 | - uses: FirebaseExtended/action-hosting-deploy@v0 26 | with: 27 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 28 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 29 | channelId: live 30 | projectId: fir-recipes-15644 31 | env: 32 | FIREBASE_CLI_PREVIEWS: hostingchannels 33 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | "on": pull_request 6 | jobs: 7 | build_and_preview: 8 | runs-on: ubuntu-latest 9 | env: 10 | REACT_APP_API_KEY: "${{ secrets.REACT_APP_API_KEY }}" 11 | REACT_APP_AUTH_DOMAIN: "${{ secrets.REACT_APP_AUTH_DOMAIN }}" 12 | REACT_APP_DATABASE_URL: "${{ secrets.REACT_APP_DATABASE_URL }}" 13 | REACT_APP_PROJECT_ID: "${{ secrets.REACT_APP_PROJECT_ID }}" 14 | REACT_APP_STORAGE_BUCKET: "${{ secrets.REACT_APP_STORAGE_BUCKET }}" 15 | REACT_APP_MESSAGING_SENDER_ID: "${{ secrets.REACT_APP_MESSAGING_SENDER_ID }}" 16 | REACT_APP_APP_ID: "${{ secrets.REACT_APP_APP_ID }}" 17 | REACT_APP_MEASUREMENT_ID: "${{ secrets.REACT_APP_MEASUREMENT_ID }}" 18 | steps: 19 | - uses: actions/checkout@v2 20 | - run: npm install 21 | - run: npm run build 22 | - uses: FirebaseExtended/action-hosting-deploy@v0 23 | with: 24 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 25 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_FIR_RECIPES_15644 }}" 26 | projectId: fir-recipes-15644 27 | env: 28 | FIREBASE_CLI_PREVIEWS: hostingchannels 29 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | .env -------------------------------------------------------------------------------- /5-Firebase-Storage/end/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. -------------------------------------------------------------------------------- /5-Firebase-Storage/end/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "uuid": "8.3.1", 14 | "web-vitals": "^0.2.4" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject", 21 | "buildDeploy": "yarn build && firebase deploy --only hosting", 22 | "setCors": "gsutil cors set cors.json gs://fir-recipes-15644.appspot.com" 23 | }, 24 | "eslintConfig": { 25 | "extends": [ 26 | "react-app", 27 | "react-app/jest" 28 | ] 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/5-Firebase-Storage/end/public/favicon.ico -------------------------------------------------------------------------------- /5-Firebase-Storage/end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/5-Firebase-Storage/end/public/logo192.png -------------------------------------------------------------------------------- /5-Firebase-Storage/end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/5-Firebase-Storage/end/public/logo512.png -------------------------------------------------------------------------------- /5-Firebase-Storage/end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | registerUser, 35 | loginUser, 36 | logoutUser, 37 | sendPasswordResetEmail, 38 | loginWithGoogle, 39 | subscribeToAuthChanges, 40 | }; 41 | 42 | export default FirebaseAuthService; 43 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/FirebaseFirestoreService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const firestore = firebase.firestore(); 4 | 5 | const createDocument = (collection, document) => { 6 | return firestore.collection(collection).add(document); 7 | }; 8 | 9 | const readDocument = (collection, id) => { 10 | return firestore.collection(collection).doc(id).get(); 11 | }; 12 | 13 | const readDocuments = async ({ 14 | collection, 15 | queries, 16 | orderByField, 17 | orderByDirection, 18 | perPage, 19 | cursorId, 20 | }) => { 21 | let collectionRef = firestore.collection(collection); 22 | 23 | if (queries && queries.length > 0) { 24 | for (const query of queries) { 25 | collectionRef = collectionRef.where( 26 | query.field, 27 | query.condition, 28 | query.value 29 | ); 30 | } 31 | } 32 | 33 | if (orderByField && orderByDirection) { 34 | collectionRef = collectionRef.orderBy(orderByField, orderByDirection); 35 | } 36 | 37 | if (perPage) { 38 | collectionRef = collectionRef.limit(perPage); 39 | } 40 | 41 | if (cursorId) { 42 | const document = await readDocument(collection, cursorId); 43 | 44 | collectionRef = collectionRef.startAfter(document); 45 | } 46 | 47 | return collectionRef.get(); 48 | }; 49 | 50 | const updateDocument = (collection, id, document) => { 51 | return firestore.collection(collection).doc(id).update(document); 52 | }; 53 | 54 | const deleteDocument = (collection, id) => { 55 | return firestore.collection(collection).doc(id).delete(); 56 | }; 57 | 58 | const FirebaseFirestoreService = { 59 | createDocument, 60 | readDocuments, 61 | updateDocument, 62 | deleteDocument, 63 | }; 64 | 65 | export default FirebaseFirestoreService; 66 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/FirebaseStorageService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const storageRef = firebase.storage().ref(); 4 | 5 | const uploadFile = (file, fullFilePath, progressCallback) => { 6 | const uploadTask = storageRef.child(fullFilePath).put(file); 7 | 8 | uploadTask.on( 9 | "state_changed", 10 | (snapshot) => { 11 | const progress = Math.round( 12 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100 13 | ); 14 | 15 | progressCallback(progress); 16 | }, 17 | (error) => { 18 | throw error; 19 | } 20 | ); 21 | 22 | return uploadTask.then(async () => { 23 | const downloadUrl = await uploadTask.snapshot.ref.getDownloadURL(); 24 | 25 | return downloadUrl; 26 | }); 27 | }; 28 | 29 | const deleteFile = (fileDownloadUrl) => { 30 | const decodedUrl = decodeURIComponent(fileDownloadUrl); 31 | const startIndex = decodedUrl.indexOf("/o/") + 3; 32 | const endIndex = decodedUrl.indexOf("?"); 33 | const filePath = decodedUrl.substring(startIndex, endIndex); 34 | 35 | return storageRef.child(filePath).delete(); 36 | }; 37 | 38 | const FirebaseStorageService = { 39 | uploadFile, 40 | deleteFile, 41 | }; 42 | 43 | export default FirebaseStorageService; 44 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /5-Firebase-Storage/end/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. -------------------------------------------------------------------------------- /5-Firebase-Storage/start/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "web-vitals": "^0.2.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject", 20 | "buildDeploy": "yarn build && firebase deploy --only hosting" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/5-Firebase-Storage/start/public/favicon.ico -------------------------------------------------------------------------------- /5-Firebase-Storage/start/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/5-Firebase-Storage/start/public/logo192.png -------------------------------------------------------------------------------- /5-Firebase-Storage/start/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/5-Firebase-Storage/start/public/logo512.png -------------------------------------------------------------------------------- /5-Firebase-Storage/start/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | registerUser, 35 | loginUser, 36 | logoutUser, 37 | sendPasswordResetEmail, 38 | loginWithGoogle, 39 | subscribeToAuthChanges, 40 | }; 41 | 42 | export default FirebaseAuthService; 43 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/FirebaseFirestoreService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const firestore = firebase.firestore(); 4 | 5 | const createDocument = (collection, document) => { 6 | return firestore.collection(collection).add(document); 7 | }; 8 | 9 | const readDocument = (collection, id) => { 10 | return firestore.collection(collection).doc(id).get(); 11 | }; 12 | 13 | const readDocuments = async ({ 14 | collection, 15 | queries, 16 | orderByField, 17 | orderByDirection, 18 | perPage, 19 | cursorId, 20 | }) => { 21 | let collectionRef = firestore.collection(collection); 22 | 23 | if (queries && queries.length > 0) { 24 | for (const query of queries) { 25 | collectionRef = collectionRef.where( 26 | query.field, 27 | query.condition, 28 | query.value 29 | ); 30 | } 31 | } 32 | 33 | if (orderByField && orderByDirection) { 34 | collectionRef = collectionRef.orderBy(orderByField, orderByDirection); 35 | } 36 | 37 | if (perPage) { 38 | collectionRef = collectionRef.limit(perPage); 39 | } 40 | 41 | if (cursorId) { 42 | const document = await readDocument(collection, cursorId); 43 | 44 | collectionRef = collectionRef.startAfter(document); 45 | } 46 | 47 | return collectionRef.get(); 48 | }; 49 | 50 | const updateDocument = (collection, id, document) => { 51 | return firestore.collection(collection).doc(id).update(document); 52 | }; 53 | 54 | const deleteDocument = (collection, id) => { 55 | return firestore.collection(collection).doc(id).delete(); 56 | }; 57 | 58 | const FirebaseFirestoreService = { 59 | createDocument, 60 | readDocuments, 61 | updateDocument, 62 | deleteDocument, 63 | }; 64 | 65 | export default FirebaseFirestoreService; 66 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /5-Firebase-Storage/start/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "fir-recipes-15644" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. 2 | 3 | This section added this value to the `.env` file 4 | REACT_APP_CLOUD_FIRESTORE_FUNCTION_API_URL= -------------------------------------------------------------------------------- /6-Firebase-Functions/end/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | }, 16 | "emulators": { 17 | "functions": { 18 | "port": 5001 19 | }, 20 | "hosting": { 21 | "port": 5000 22 | }, 23 | "ui": { 24 | "enabled": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/functions/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /6-Firebase-Functions/end/functions/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | const functions = require("firebase-functions"); 2 | const admin = require("firebase-admin"); 3 | 4 | const FIREBASE_STORAGE_BUCKET = "fir-recipes-15644.appspot.com"; 5 | 6 | const apiFirebaseOptions = { 7 | ...functions.config().firebase, 8 | credential: admin.credential.applicationDefault(), 9 | }; 10 | 11 | admin.initializeApp(apiFirebaseOptions); 12 | 13 | const firestore = admin.firestore(); 14 | const settings = { timestampsInSnapshots: true }; 15 | 16 | firestore.settings(settings); 17 | 18 | const storageBucket = admin.storage().bucket(FIREBASE_STORAGE_BUCKET); 19 | const auth = admin.auth(); 20 | 21 | module.exports = { functions, auth, firestore, storageBucket, admin }; 22 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "firebase emulators:start --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "12" 13 | }, 14 | "main": "index.js", 15 | "dependencies": { 16 | "firebase-admin": "^9.2.0", 17 | "firebase-functions": "^3.11.0" 18 | }, 19 | "devDependencies": { 20 | "firebase-functions-test": "^0.2.0" 21 | }, 22 | "private": true 23 | } 24 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/functions/utilities.js: -------------------------------------------------------------------------------- 1 | const authorizeUser = async (authorizationHeader, firebaseAuth) => { 2 | if (!authorizationHeader) { 3 | // eslint-disable-next-line no-throw-literal 4 | throw "no authorization provided!"; 5 | } 6 | 7 | const token = authorizationHeader.split(" ")[1]; 8 | 9 | try { 10 | const decodedToken = await firebaseAuth.verifyIdToken(token); 11 | 12 | return decodedToken; 13 | } catch (error) { 14 | throw error; 15 | } 16 | }; 17 | 18 | const validateRecipePostPut = (newRecipe) => { 19 | let missingFields = ""; 20 | 21 | if (!newRecipe) { 22 | missingFields += "recipe"; 23 | 24 | return missingFields; 25 | } 26 | 27 | if (!newRecipe.name) { 28 | missingFields += "name"; 29 | } 30 | 31 | if (!newRecipe.category) { 32 | missingFields += "category"; 33 | } 34 | 35 | if (!newRecipe.directions) { 36 | missingFields += "directions"; 37 | } 38 | 39 | if (newRecipe.isPublished !== true && newRecipe.isPublished !== false) { 40 | missingFields += "isPublished"; 41 | } 42 | 43 | if (!newRecipe.publishDate) { 44 | missingFields += "publishDate"; 45 | } 46 | 47 | if (!newRecipe.ingredients || newRecipe.ingredients.length === 0) { 48 | missingFields += "ingredients"; 49 | } 50 | 51 | if (!newRecipe.imageUrl) { 52 | missingFields += "imageUrl"; 53 | } 54 | 55 | return missingFields; 56 | }; 57 | 58 | const sanitizeRecipePostPut = (newRecipe) => { 59 | const recipe = {}; 60 | 61 | recipe.name = newRecipe.name; 62 | recipe.category = newRecipe.category; 63 | recipe.directions = newRecipe.directions; 64 | recipe.publishDate = new Date(newRecipe.publishDate * 1000); 65 | recipe.isPublished = newRecipe.isPublished; 66 | recipe.ingredients = newRecipe.ingredients; 67 | recipe.imageUrl = newRecipe.imageUrl; 68 | 69 | return recipe; 70 | }; 71 | 72 | module.exports = { 73 | authorizeUser, 74 | validateRecipePostPut, 75 | sanitizeRecipePostPut, 76 | }; 77 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "body-parser": "1.19.0", 10 | "cors": "2.8.5", 11 | "express": "4.17.1", 12 | "firebase": "8.9.1", 13 | "react": "^17.0.1", 14 | "react-dom": "^17.0.1", 15 | "react-scripts": "4.0.0", 16 | "uuid": "8.3.1", 17 | "web-vitals": "^0.2.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject", 24 | "buildDeploy": "yarn build && firebase deploy --only hosting", 25 | "setCors": "gsutil cors set cors.json gs://fir-recipes-15644.appspot.com" 26 | }, 27 | "eslintConfig": { 28 | "extends": [ 29 | "react-app", 30 | "react-app/jest" 31 | ] 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/6-Firebase-Functions/end/public/favicon.ico -------------------------------------------------------------------------------- /6-Firebase-Functions/end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/6-Firebase-Functions/end/public/logo192.png -------------------------------------------------------------------------------- /6-Firebase-Functions/end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/6-Firebase-Functions/end/public/logo512.png -------------------------------------------------------------------------------- /6-Firebase-Functions/end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | registerUser, 35 | loginUser, 36 | logoutUser, 37 | sendPasswordResetEmail, 38 | loginWithGoogle, 39 | subscribeToAuthChanges, 40 | }; 41 | 42 | export default FirebaseAuthService; 43 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/FirebaseFirestoreService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const firestore = firebase.firestore(); 4 | 5 | const createDocument = (collection, document) => { 6 | return firestore.collection(collection).add(document); 7 | }; 8 | 9 | const readDocument = (collection, id) => { 10 | return firestore.collection(collection).doc(id).get(); 11 | }; 12 | 13 | const readDocuments = async ({ 14 | collection, 15 | queries, 16 | orderByField, 17 | orderByDirection, 18 | perPage, 19 | cursorId, 20 | }) => { 21 | let collectionRef = firestore.collection(collection); 22 | 23 | if (queries && queries.length > 0) { 24 | for (const query of queries) { 25 | collectionRef = collectionRef.where( 26 | query.field, 27 | query.condition, 28 | query.value 29 | ); 30 | } 31 | } 32 | 33 | if (orderByField && orderByDirection) { 34 | collectionRef = collectionRef.orderBy(orderByField, orderByDirection); 35 | } 36 | 37 | if (perPage) { 38 | collectionRef = collectionRef.limit(perPage); 39 | } 40 | 41 | if (cursorId) { 42 | const document = await readDocument(collection, cursorId); 43 | 44 | collectionRef = collectionRef.startAfter(document); 45 | } 46 | 47 | return collectionRef.get(); 48 | }; 49 | 50 | const updateDocument = (collection, id, document) => { 51 | return firestore.collection(collection).doc(id).update(document); 52 | }; 53 | 54 | const deleteDocument = (collection, id) => { 55 | return firestore.collection(collection).doc(id).delete(); 56 | }; 57 | 58 | const FirebaseFirestoreService = { 59 | createDocument, 60 | readDocuments, 61 | updateDocument, 62 | deleteDocument, 63 | }; 64 | 65 | export default FirebaseFirestoreService; 66 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/FirebaseStorageService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const storageRef = firebase.storage().ref(); 4 | 5 | const uploadFile = (file, fullFilePath, progressCallback) => { 6 | const uploadTask = storageRef.child(fullFilePath).put(file); 7 | 8 | uploadTask.on( 9 | "state_changed", 10 | (snapshot) => { 11 | const progress = Math.round( 12 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100 13 | ); 14 | 15 | progressCallback(progress); 16 | }, 17 | (error) => { 18 | throw error; 19 | } 20 | ); 21 | 22 | return uploadTask.then(async () => { 23 | const downloadUrl = await uploadTask.snapshot.ref.getDownloadURL(); 24 | 25 | return downloadUrl; 26 | }); 27 | }; 28 | 29 | const deleteFile = (fileDownloadUrl) => { 30 | const decodedUrl = decodeURIComponent(fileDownloadUrl); 31 | const startIndex = decodedUrl.indexOf("/o/") + 3; 32 | const endIndex = decodedUrl.indexOf("?"); 33 | const filePath = decodedUrl.substring(startIndex, endIndex); 34 | 35 | return storageRef.child(filePath).delete(); 36 | }; 37 | 38 | const FirebaseStorageService = { 39 | uploadFile, 40 | deleteFile, 41 | }; 42 | 43 | export default FirebaseStorageService; 44 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /6-Firebase-Functions/end/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. -------------------------------------------------------------------------------- /6-Firebase-Functions/start/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "firebase": "8.9.1", 10 | "react": "^17.0.1", 11 | "react-dom": "^17.0.1", 12 | "react-scripts": "4.0.0", 13 | "uuid": "8.3.1", 14 | "web-vitals": "^0.2.4" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject", 21 | "buildDeploy": "yarn build && firebase deploy --only hosting", 22 | "setCors": "gsutil cors set cors.json gs://fir-recipes-15644.appspot.com" 23 | }, 24 | "eslintConfig": { 25 | "extends": [ 26 | "react-app", 27 | "react-app/jest" 28 | ] 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/6-Firebase-Functions/start/public/favicon.ico -------------------------------------------------------------------------------- /6-Firebase-Functions/start/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/6-Firebase-Functions/start/public/logo192.png -------------------------------------------------------------------------------- /6-Firebase-Functions/start/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/6-Firebase-Functions/start/public/logo512.png -------------------------------------------------------------------------------- /6-Firebase-Functions/start/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | registerUser, 35 | loginUser, 36 | logoutUser, 37 | sendPasswordResetEmail, 38 | loginWithGoogle, 39 | subscribeToAuthChanges, 40 | }; 41 | 42 | export default FirebaseAuthService; 43 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/FirebaseFirestoreService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const firestore = firebase.firestore(); 4 | 5 | const createDocument = (collection, document) => { 6 | return firestore.collection(collection).add(document); 7 | }; 8 | 9 | const readDocument = (collection, id) => { 10 | return firestore.collection(collection).doc(id).get(); 11 | }; 12 | 13 | const readDocuments = async ({ 14 | collection, 15 | queries, 16 | orderByField, 17 | orderByDirection, 18 | perPage, 19 | cursorId, 20 | }) => { 21 | let collectionRef = firestore.collection(collection); 22 | 23 | if (queries && queries.length > 0) { 24 | for (const query of queries) { 25 | collectionRef = collectionRef.where( 26 | query.field, 27 | query.condition, 28 | query.value 29 | ); 30 | } 31 | } 32 | 33 | if (orderByField && orderByDirection) { 34 | collectionRef = collectionRef.orderBy(orderByField, orderByDirection); 35 | } 36 | 37 | if (perPage) { 38 | collectionRef = collectionRef.limit(perPage); 39 | } 40 | 41 | if (cursorId) { 42 | const document = await readDocument(collection, cursorId); 43 | 44 | collectionRef = collectionRef.startAfter(document); 45 | } 46 | 47 | return collectionRef.get(); 48 | }; 49 | 50 | const updateDocument = (collection, id, document) => { 51 | return firestore.collection(collection).doc(id).update(document); 52 | }; 53 | 54 | const deleteDocument = (collection, id) => { 55 | return firestore.collection(collection).doc(id).delete(); 56 | }; 57 | 58 | const FirebaseFirestoreService = { 59 | createDocument, 60 | readDocuments, 61 | updateDocument, 62 | deleteDocument, 63 | }; 64 | 65 | export default FirebaseFirestoreService; 66 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/FirebaseStorageService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const storageRef = firebase.storage().ref(); 4 | 5 | const uploadFile = (file, fullFilePath, progressCallback) => { 6 | const uploadTask = storageRef.child(fullFilePath).put(file); 7 | 8 | uploadTask.on( 9 | "state_changed", 10 | (snapshot) => { 11 | const progress = Math.round( 12 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100 13 | ); 14 | 15 | progressCallback(progress); 16 | }, 17 | (error) => { 18 | throw error; 19 | } 20 | ); 21 | 22 | return uploadTask.then(async () => { 23 | const downloadUrl = await uploadTask.snapshot.ref.getDownloadURL(); 24 | 25 | return downloadUrl; 26 | }); 27 | }; 28 | 29 | const deleteFile = (fileDownloadUrl) => { 30 | const decodedUrl = decodeURIComponent(fileDownloadUrl); 31 | const startIndex = decodedUrl.indexOf("/o/") + 3; 32 | const endIndex = decodedUrl.indexOf("?"); 33 | const filePath = decodedUrl.substring(startIndex, endIndex); 34 | 35 | return storageRef.child(filePath).delete(); 36 | }; 37 | 38 | const FirebaseStorageService = { 39 | uploadFile, 40 | deleteFile, 41 | }; 42 | 43 | export default FirebaseStorageService; 44 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /6-Firebase-Functions/start/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. 2 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | }, 16 | "emulators": { 17 | "functions": { 18 | "port": 5001 19 | }, 20 | "hosting": { 21 | "port": 5000 22 | }, 23 | "ui": { 24 | "enabled": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/functions/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/functions/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | const functions = require("firebase-functions"); 2 | const admin = require("firebase-admin"); 3 | 4 | const FIREBASE_STORAGE_BUCKET = "fir-recipes-15644.appspot.com"; 5 | 6 | const apiFirebaseOptions = { 7 | ...functions.config().firebase, 8 | credential: admin.credential.applicationDefault(), 9 | }; 10 | 11 | admin.initializeApp(apiFirebaseOptions); 12 | 13 | const firestore = admin.firestore(); 14 | const settings = { timestampsInSnapshots: true }; 15 | 16 | firestore.settings(settings); 17 | 18 | const storageBucket = admin.storage().bucket(FIREBASE_STORAGE_BUCKET); 19 | const auth = admin.auth(); 20 | 21 | module.exports = { functions, auth, firestore, storageBucket, admin }; 22 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "firebase emulators:start --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "12" 13 | }, 14 | "main": "index.js", 15 | "dependencies": { 16 | "firebase-admin": "^9.2.0", 17 | "firebase-functions": "^3.11.0" 18 | }, 19 | "devDependencies": { 20 | "firebase-functions-test": "^0.2.0" 21 | }, 22 | "private": true 23 | } 24 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/functions/utilities.js: -------------------------------------------------------------------------------- 1 | const authorizeUser = async (authorizationHeader, firebaseAuth) => { 2 | if (!authorizationHeader) { 3 | // eslint-disable-next-line no-throw-literal 4 | throw "no authorization provided!"; 5 | } 6 | 7 | const token = authorizationHeader.split(" ")[1]; 8 | 9 | try { 10 | const decodedToken = await firebaseAuth.verifyIdToken(token); 11 | 12 | return decodedToken; 13 | } catch (error) { 14 | throw error; 15 | } 16 | }; 17 | 18 | const validateRecipePostPut = (newRecipe) => { 19 | let missingFields = ""; 20 | 21 | if (!newRecipe) { 22 | missingFields += "recipe"; 23 | 24 | return missingFields; 25 | } 26 | 27 | if (!newRecipe.name) { 28 | missingFields += "name"; 29 | } 30 | 31 | if (!newRecipe.category) { 32 | missingFields += "category"; 33 | } 34 | 35 | if (!newRecipe.directions) { 36 | missingFields += "directions"; 37 | } 38 | 39 | if (newRecipe.isPublished !== true && newRecipe.isPublished !== false) { 40 | missingFields += "isPublished"; 41 | } 42 | 43 | if (!newRecipe.publishDate) { 44 | missingFields += "publishDate"; 45 | } 46 | 47 | if (!newRecipe.ingredients || newRecipe.ingredients.length === 0) { 48 | missingFields += "ingredients"; 49 | } 50 | 51 | if (!newRecipe.imageUrl) { 52 | missingFields += "imageUrl"; 53 | } 54 | 55 | return missingFields; 56 | }; 57 | 58 | const sanitizeRecipePostPut = (newRecipe) => { 59 | const recipe = {}; 60 | 61 | recipe.name = newRecipe.name; 62 | recipe.category = newRecipe.category; 63 | recipe.directions = newRecipe.directions; 64 | recipe.publishDate = new Date(newRecipe.publishDate * 1000); 65 | recipe.isPublished = newRecipe.isPublished; 66 | recipe.ingredients = newRecipe.ingredients; 67 | recipe.imageUrl = newRecipe.imageUrl; 68 | 69 | return recipe; 70 | }; 71 | 72 | module.exports = { 73 | authorizeUser, 74 | validateRecipePostPut, 75 | sanitizeRecipePostPut, 76 | }; 77 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "body-parser": "1.19.0", 10 | "cors": "2.8.5", 11 | "express": "4.17.1", 12 | "firebase": "9.0.2", 13 | "react": "^17.0.1", 14 | "react-dom": "^17.0.1", 15 | "react-scripts": "4.0.0", 16 | "uuid": "8.3.1", 17 | "web-vitals": "^0.2.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject", 24 | "buildDeploy": "yarn build && firebase deploy --only hosting", 25 | "setCors": "gsutil cors set cors.json gs://fir-recipes-15644.appspot.com" 26 | }, 27 | "eslintConfig": { 28 | "extends": [ 29 | "react-app", 30 | "react-app/jest" 31 | ] 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/favicon.ico -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/logo192.png -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/logo512.png -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from './FirebaseConfig'; 2 | import { 3 | createUserWithEmailAndPassword, 4 | signInWithEmailAndPassword, 5 | sendPasswordResetEmail, 6 | signInWithPopup, 7 | GoogleAuthProvider, 8 | onAuthStateChanged, 9 | } from 'firebase/auth'; 10 | 11 | const auth = firebase.auth; 12 | 13 | const registerUser = (email, password) => { 14 | return createUserWithEmailAndPassword(auth, email, password); 15 | }; 16 | 17 | const loginUser = (email, password) => { 18 | return signInWithEmailAndPassword(auth, email, password); 19 | }; 20 | 21 | const logoutUser = () => { 22 | return auth.signOut(); 23 | }; 24 | 25 | const loginWithGoogle = () => { 26 | const provider = new GoogleAuthProvider(); 27 | 28 | return signInWithPopup(auth, provider); 29 | }; 30 | 31 | const subscribeToAuthChanges = (handleAuthChange) => { 32 | onAuthStateChanged(auth, (user) => { 33 | handleAuthChange(user); 34 | }); 35 | }; 36 | 37 | const FirebaseAuthService = { 38 | registerUser, 39 | loginUser, 40 | logoutUser, 41 | sendPasswordResetEmail: (email) => { 42 | sendPasswordResetEmail(auth, email); 43 | }, 44 | loginWithGoogle, 45 | subscribeToAuthChanges, 46 | }; 47 | 48 | export default FirebaseAuthService; 49 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | // v9 compat packages are API compatible with v8 code 2 | // import firebase from 'firebase/compat/app'; 3 | // import 'firebase/compat/auth'; 4 | // import 'firebase/compat/firestore'; 5 | // import 'firebase/compat/storage'; 6 | 7 | import { initializeApp } from 'firebase/app'; 8 | import { getAuth } from 'firebase/auth'; 9 | // import { getFirestore } from 'firebase/firestore'; 10 | import { getFirestore } from 'firebase/firestore/lite'; 11 | import { getStorage } from 'firebase/storage'; 12 | 13 | const config = { 14 | apiKey: process.env.REACT_APP_API_KEY, 15 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 16 | databaseURL: process.env.REACT_APP_DATABASE_URL, 17 | projectId: process.env.REACT_APP_PROJECT_ID, 18 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 19 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 20 | appId: process.env.REACT_APP_APP_ID, 21 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 22 | }; 23 | 24 | // Version 8 25 | // const classicFirebaseApp = firebase.initializeApp(config); 26 | // const firestore = classicFirebaseApp.firestore; 27 | // const storage = classicFirebaseApp.storage(); 28 | 29 | // Version 9 30 | const firebaseApp = initializeApp(config); 31 | const auth = getAuth(firebaseApp); 32 | const firestore = getFirestore(firebaseApp); 33 | const storage = getStorage(firebaseApp); 34 | 35 | const firebaseConfig = { 36 | auth, 37 | firestore, 38 | storage, 39 | }; 40 | 41 | export default firebaseConfig; 42 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/FirebaseFirestoreService.js: -------------------------------------------------------------------------------- 1 | import firebase from './FirebaseConfig'; 2 | 3 | import { 4 | addDoc, 5 | doc, 6 | getDoc, 7 | collection as firestoreCollection, 8 | query, 9 | where, 10 | orderBy, 11 | limit, 12 | startAfter, 13 | getDocs, 14 | updateDoc, 15 | deleteDoc, 16 | } from 'firebase/firestore/lite'; 17 | 18 | const firestore = firebase.firestore; 19 | 20 | const createDocument = (collection, document) => { 21 | return addDoc(firestoreCollection(firestore, collection), document); 22 | }; 23 | 24 | const readDocument = (collection, id) => { 25 | return getDoc(doc(firestore, collection, id)); 26 | }; 27 | 28 | const readDocuments = async ({ 29 | collection, 30 | queries, 31 | orderByField, 32 | orderByDirection, 33 | perPage, 34 | cursorId, 35 | }) => { 36 | const collectionRef = firestoreCollection(firestore, collection); 37 | 38 | const queryConstraints = []; 39 | 40 | if (queries && queries.length > 0) { 41 | for (const query of queries) { 42 | queryConstraints.push(where(query.field, query.condition, query.value)); 43 | } 44 | } 45 | 46 | if (orderByField && orderByDirection) { 47 | queryConstraints.push(orderBy(orderByField, orderByDirection)); 48 | } 49 | 50 | if (perPage) { 51 | queryConstraints.push(limit(perPage)); 52 | } 53 | 54 | if (cursorId) { 55 | const document = await readDocument(collection, cursorId); 56 | 57 | queryConstraints.push(startAfter(document)); 58 | } 59 | 60 | const firestoreQuery = query(collectionRef, ...queryConstraints); 61 | 62 | return getDocs(firestoreQuery); 63 | }; 64 | 65 | const updateDocument = (collection, id, document) => { 66 | return updateDoc(doc(firestore, collection, id), document); 67 | }; 68 | 69 | const deleteDocument = (collection, id) => { 70 | return deleteDoc(doc(firestore, collection, id)); 71 | }; 72 | 73 | const FirebaseFirestoreService = { 74 | createDocument, 75 | readDocuments, 76 | updateDocument, 77 | deleteDocument, 78 | }; 79 | 80 | export default FirebaseFirestoreService; 81 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/FirebaseStorageService.js: -------------------------------------------------------------------------------- 1 | import firebase from './FirebaseConfig'; 2 | 3 | import { 4 | ref, 5 | uploadBytesResumable, 6 | getDownloadURL, 7 | deleteObject, 8 | } from 'firebase/storage'; 9 | 10 | const storage = firebase.storage; 11 | 12 | const uploadFile = (file, fullFilePath, progressCallback) => { 13 | const uploadRef = ref(storage, fullFilePath); 14 | const uploadTask = uploadBytesResumable(uploadRef, file); 15 | 16 | uploadTask.on( 17 | 'state_changed', 18 | (snapshot) => { 19 | const progress = Math.round( 20 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100 21 | ); 22 | 23 | progressCallback(progress); 24 | }, 25 | (error) => { 26 | throw error; 27 | } 28 | ); 29 | 30 | return uploadTask.then(async () => { 31 | const downloadUrl = await getDownloadURL(uploadTask.snapshot.ref); 32 | 33 | return downloadUrl; 34 | }); 35 | }; 36 | 37 | const deleteFile = (fileDownloadUrl) => { 38 | const decodedUrl = decodeURIComponent(fileDownloadUrl); 39 | const startIndex = decodedUrl.indexOf('/o/') + 3; 40 | const endIndex = decodedUrl.indexOf('?'); 41 | const filePath = decodedUrl.substring(startIndex, endIndex); 42 | 43 | const fileRef = ref(storage, filePath); 44 | 45 | return deleteObject(fileRef); 46 | }; 47 | 48 | const FirebaseStorageService = { 49 | uploadFile, 50 | deleteFile, 51 | }; 52 | 53 | export default FirebaseStorageService; 54 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/end/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/README.md: -------------------------------------------------------------------------------- 1 | This project requires the `.env` file created in section 2. 2 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | }, 16 | "emulators": { 17 | "functions": { 18 | "port": 5001 19 | }, 20 | "hosting": { 21 | "port": 5000 22 | }, 23 | "ui": { 24 | "enabled": true 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/functions/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/functions/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | const functions = require("firebase-functions"); 2 | const admin = require("firebase-admin"); 3 | 4 | const FIREBASE_STORAGE_BUCKET = "fir-recipes-15644.appspot.com"; 5 | 6 | const apiFirebaseOptions = { 7 | ...functions.config().firebase, 8 | credential: admin.credential.applicationDefault(), 9 | }; 10 | 11 | admin.initializeApp(apiFirebaseOptions); 12 | 13 | const firestore = admin.firestore(); 14 | const settings = { timestampsInSnapshots: true }; 15 | 16 | firestore.settings(settings); 17 | 18 | const storageBucket = admin.storage().bucket(FIREBASE_STORAGE_BUCKET); 19 | const auth = admin.auth(); 20 | 21 | module.exports = { functions, auth, firestore, storageBucket, admin }; 22 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "firebase emulators:start --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "12" 13 | }, 14 | "main": "index.js", 15 | "dependencies": { 16 | "firebase-admin": "^9.2.0", 17 | "firebase-functions": "^3.11.0" 18 | }, 19 | "devDependencies": { 20 | "firebase-functions-test": "^0.2.0" 21 | }, 22 | "private": true 23 | } 24 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/functions/utilities.js: -------------------------------------------------------------------------------- 1 | const authorizeUser = async (authorizationHeader, firebaseAuth) => { 2 | if (!authorizationHeader) { 3 | // eslint-disable-next-line no-throw-literal 4 | throw "no authorization provided!"; 5 | } 6 | 7 | const token = authorizationHeader.split(" ")[1]; 8 | 9 | try { 10 | const decodedToken = await firebaseAuth.verifyIdToken(token); 11 | 12 | return decodedToken; 13 | } catch (error) { 14 | throw error; 15 | } 16 | }; 17 | 18 | const validateRecipePostPut = (newRecipe) => { 19 | let missingFields = ""; 20 | 21 | if (!newRecipe) { 22 | missingFields += "recipe"; 23 | 24 | return missingFields; 25 | } 26 | 27 | if (!newRecipe.name) { 28 | missingFields += "name"; 29 | } 30 | 31 | if (!newRecipe.category) { 32 | missingFields += "category"; 33 | } 34 | 35 | if (!newRecipe.directions) { 36 | missingFields += "directions"; 37 | } 38 | 39 | if (newRecipe.isPublished !== true && newRecipe.isPublished !== false) { 40 | missingFields += "isPublished"; 41 | } 42 | 43 | if (!newRecipe.publishDate) { 44 | missingFields += "publishDate"; 45 | } 46 | 47 | if (!newRecipe.ingredients || newRecipe.ingredients.length === 0) { 48 | missingFields += "ingredients"; 49 | } 50 | 51 | if (!newRecipe.imageUrl) { 52 | missingFields += "imageUrl"; 53 | } 54 | 55 | return missingFields; 56 | }; 57 | 58 | const sanitizeRecipePostPut = (newRecipe) => { 59 | const recipe = {}; 60 | 61 | recipe.name = newRecipe.name; 62 | recipe.category = newRecipe.category; 63 | recipe.directions = newRecipe.directions; 64 | recipe.publishDate = new Date(newRecipe.publishDate * 1000); 65 | recipe.isPublished = newRecipe.isPublished; 66 | recipe.ingredients = newRecipe.ingredients; 67 | recipe.imageUrl = newRecipe.imageUrl; 68 | 69 | return recipe; 70 | }; 71 | 72 | module.exports = { 73 | authorizeUser, 74 | validateRecipePostPut, 75 | sanitizeRecipePostPut, 76 | }; 77 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-recipes-web-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.4", 7 | "@testing-library/react": "^11.1.0", 8 | "@testing-library/user-event": "^12.1.10", 9 | "body-parser": "1.19.0", 10 | "cors": "2.8.5", 11 | "express": "4.17.1", 12 | "firebase": "8.9.1", 13 | "react": "^17.0.1", 14 | "react-dom": "^17.0.1", 15 | "react-scripts": "4.0.0", 16 | "uuid": "8.3.1", 17 | "web-vitals": "^0.2.4" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject", 24 | "buildDeploy": "yarn build && firebase deploy --only hosting", 25 | "setCors": "gsutil cors set cors.json gs://fir-recipes-15644.appspot.com" 26 | }, 27 | "eslintConfig": { 28 | "extends": [ 29 | "react-app", 30 | "react-app/jest" 31 | ] 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/favicon.ico -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/logo192.png -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaredPotter/firebase-core-with-react/938af2e2c5993aa619aefcd5e0e603a362a32d06/7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/logo512.png -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/FirebaseAuthService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const auth = firebase.auth(); 4 | 5 | const registerUser = (email, password) => { 6 | return auth.createUserWithEmailAndPassword(email, password); 7 | }; 8 | 9 | const loginUser = (email, password) => { 10 | return auth.signInWithEmailAndPassword(email, password); 11 | }; 12 | 13 | const logoutUser = () => { 14 | return auth.signOut(); 15 | }; 16 | 17 | const sendPasswordResetEmail = (email) => { 18 | return auth.sendPasswordResetEmail(email); 19 | }; 20 | 21 | const loginWithGoogle = () => { 22 | const provider = new firebase.auth.GoogleAuthProvider(); 23 | 24 | return auth.signInWithPopup(provider); 25 | }; 26 | 27 | const subscribeToAuthChanges = (handleAuthChange) => { 28 | auth.onAuthStateChanged((user) => { 29 | handleAuthChange(user); 30 | }); 31 | }; 32 | 33 | const FirebaseAuthService = { 34 | registerUser, 35 | loginUser, 36 | logoutUser, 37 | sendPasswordResetEmail, 38 | loginWithGoogle, 39 | subscribeToAuthChanges, 40 | }; 41 | 42 | export default FirebaseAuthService; 43 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/FirebaseConfig.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | 3 | const config = { 4 | apiKey: process.env.REACT_APP_API_KEY, 5 | authDomain: process.env.REACT_APP_AUTH_DOMAIN, 6 | databaseURL: process.env.REACT_APP_DATABASE_URL, 7 | projectId: process.env.REACT_APP_PROJECT_ID, 8 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET, 9 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID, 10 | appId: process.env.REACT_APP_APP_ID, 11 | measurementId: process.env.REACT_APP_MEASUREMENT_ID, 12 | }; 13 | 14 | if (!firebase.apps.length) { 15 | firebase.initializeApp(config); 16 | } 17 | 18 | export default firebase; 19 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/FirebaseFirestoreService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const firestore = firebase.firestore(); 4 | 5 | const createDocument = (collection, document) => { 6 | return firestore.collection(collection).add(document); 7 | }; 8 | 9 | const readDocument = (collection, id) => { 10 | return firestore.collection(collection).doc(id).get(); 11 | }; 12 | 13 | const readDocuments = async ({ 14 | collection, 15 | queries, 16 | orderByField, 17 | orderByDirection, 18 | perPage, 19 | cursorId, 20 | }) => { 21 | let collectionRef = firestore.collection(collection); 22 | 23 | if (queries && queries.length > 0) { 24 | for (const query of queries) { 25 | collectionRef = collectionRef.where( 26 | query.field, 27 | query.condition, 28 | query.value 29 | ); 30 | } 31 | } 32 | 33 | if (orderByField && orderByDirection) { 34 | collectionRef = collectionRef.orderBy(orderByField, orderByDirection); 35 | } 36 | 37 | if (perPage) { 38 | collectionRef = collectionRef.limit(perPage); 39 | } 40 | 41 | if (cursorId) { 42 | const document = await readDocument(collection, cursorId); 43 | 44 | collectionRef = collectionRef.startAfter(document); 45 | } 46 | 47 | return collectionRef.get(); 48 | }; 49 | 50 | const updateDocument = (collection, id, document) => { 51 | return firestore.collection(collection).doc(id).update(document); 52 | }; 53 | 54 | const deleteDocument = (collection, id) => { 55 | return firestore.collection(collection).doc(id).delete(); 56 | }; 57 | 58 | const FirebaseFirestoreService = { 59 | createDocument, 60 | readDocuments, 61 | updateDocument, 62 | deleteDocument, 63 | }; 64 | 65 | export default FirebaseFirestoreService; 66 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/FirebaseStorageService.js: -------------------------------------------------------------------------------- 1 | import firebase from "./FirebaseConfig"; 2 | 3 | const storageRef = firebase.storage().ref(); 4 | 5 | const uploadFile = (file, fullFilePath, progressCallback) => { 6 | const uploadTask = storageRef.child(fullFilePath).put(file); 7 | 8 | uploadTask.on( 9 | "state_changed", 10 | (snapshot) => { 11 | const progress = Math.round( 12 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100 13 | ); 14 | 15 | progressCallback(progress); 16 | }, 17 | (error) => { 18 | throw error; 19 | } 20 | ); 21 | 22 | return uploadTask.then(async () => { 23 | const downloadUrl = await uploadTask.snapshot.ref.getDownloadURL(); 24 | 25 | return downloadUrl; 26 | }); 27 | }; 28 | 29 | const deleteFile = (fileDownloadUrl) => { 30 | const decodedUrl = decodeURIComponent(fileDownloadUrl); 31 | const startIndex = decodedUrl.indexOf("/o/") + 3; 32 | const endIndex = decodedUrl.indexOf("?"); 33 | const filePath = decodedUrl.substring(startIndex, endIndex); 34 | 35 | return storageRef.child(filePath).delete(); 36 | }; 37 | 38 | const FirebaseStorageService = { 39 | uploadFile, 40 | deleteFile, 41 | }; 42 | 43 | export default FirebaseStorageService; 44 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /7-Firebase-Web-NPM-JavaScript-SDK-Version-9/start/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This course uses node version 14 - specifically 14.17.6. 2 | 3 | This course uses the Firebase Web NPM Package version 8.9.1 (version 8). 4 | In September 2021 Firebase released version 9 of the Firebase Web NPM Package that has greater support for tree-shaking optimization (to reduce bundle size). However, version 8 is still fully documented and supported and will be maintained for quite some time. 5 | --------------------------------------------------------------------------------