├── .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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------