User Authorization with Firebase Walkthrough

User Authorization with Firebase Walkthrough

Useful Links

What is Firebase?

Firebase concept is simple. When you build a client-side app with JavaScript or any of its frameworks, for instance, Google Firebase can turn this into a serverless app in no time. It also removes the need to manage databases yourself, as it does that for you.

Firebase is a backend platform for building Web, Android and IOS applications. It offers real time database, different APIs, multiple authentication types and hosting platform.

Adding Firebase

  1. Go to Firebase
  2. Login and Create New Project
  3. Give your project a name
  4. Accept terms and options SEO
  5. From within your apps console
    1. Register your app
    2. Install firebase via NPM
      • npm i firebase
    3. Copy config file firebase provides
    4. add firebaseConfig.js inside config folder inside of src and paste our config
    5. Recommend add .gitignore and configuring .env file for firebaseConfig
    6. export default firebaseConfig

Choosing our Firebase Build

  1. In this project we want to choose Authentication
  2. We want to add Email/Password for Native providers
  3. Google for Additional Providers
    1. Confirm Project public-facing-name, typically default is fine.
    2. Add Project support email and Save

Integrating Firebase to your project

  1. Create a new file called firebase.js in your src folder

  2. Inside lets create the const firebaseApp and initialize with our firebaseConfig file

    1. Don't forget to import initialize from firebase/app
  3. Create const auth = getAuth(firebaseApp)

  4. Import the auth library from 'firebase/auth'

  5. Create const db = getFirestore(firebaseApp)

  6. Import firestore library from 'firebase/firestore'

  7. Export auth and db to be utilized outside of this file.

Completed Example of 'firebase.js'

1import firebaseConfig from './config/firebaseConfig';
2import { initializeApp } from 'firebase/app';
3import { getAuth } from 'firebase/auth';
4import { getFirestore } from 'firebase/firestore';
5
6const firebaseApp = initializeApp(firebaseConfig);
7
8const auth = getAuth(firebaseApp);
9const db = getFirestore(firebaseApp);
10
11export { auth, db };
12

Adding to our Context State

  • In our Crypto Demo application we utilize Context API so we can tap into our state object without prop drilling.
  • Since we want to add this to Login and have our user status accessible throughout the application this is an ideal location to configure
  1. Add user state to our crypto context.

CryptoContext Example

1const CryptoContext = ({ children }) => {
2  const [currency, setCurrency] = useState('INR');
3  const [symbol, setSymbol] = useState('₹');
4  const [coins, setCoins] = useState([]);
5  const [loading, setLoading] = useState(false);
6  const [user, setUser] = useState(null)
7
  1. Add Material UI Modal Component for Login Button

    1. Inside of Components folder lets make Authentication folder
    2. Lets add AuthModal.js to the Authentication folder
      1. Copy Modal of Choice from MUI website and paste into AuthModal.js and rename the modal export to AuthModal
      2. Inside of Header.js Lets add <AuthModal/> after Select but inside of Toolbar. Remember to Import.
      3. Lets Remove the default button and add our own next in AuthModal.js
  2. Add <Button> from Material-UI

    1. Login will be the content of the button
    2. variant will be 'contained'
    3. style get from example below
    4. Add onClick={handleOpen}

New MUI Button

1<Button
2  variant="contained"
3  style={{
4    width: 85,
5    height: 40,
6    marginLeft: 15,
7    backgroundColor: '#EEBC1D',
8  }}
9>
10  Login
11</Button>
12
  1. Update Fade Component inside our AuthModal

    1. Remove all default tags inside our <div> inside of <Fade>
    2. Add MUI TABS component to our Auth Modal
      1. Import Tabs
      2. Add <AppBar> inside our div
      3. Notice that tabs needs 'value' and 'handleChange'
      4. Lets copy that from our TABS code from MUI documentation
  2. Add styles to paper for useStyles inside our modal on AuthModal.js

1
2const useStyles = makeStyles((theme) => ({
3  modal: {
4    display: 'flex',
5    alignItems: 'center',
6    justifyContent: 'center',
7  },
8  paper: {
9    width: 400,
10    backgroundColor: theme.palette.background.paper,
11    color: 'white',
12    borderRadius: 10,
13  }
14}));
15

Updating the TAB logic

  1. Add {value===0 && <Login/>} inside our AuthMOdal After </AppBar>
  2. Add {value ===1 && <SignUp/>} inside our AuthMOdal After </AppBar>
  3. Create Login and SignUp Components Inside our Authentication Folder

Configuring Login & Signup

  1. Import Login and SignUp to AuthModal.js
  2. We want to use handleClose method inside our Login and SignUp Componenents
    1. Lets pass handleClose down as a prop
    2. Add props inside our Login And SignUp Components so we can use them.

Example of HandleClose

1{
2  value === 0 && <Login handleClose={handleClose} />;
3}
4{
5  value === 1 && <SignUp handleClose={handleClose} />;
6}
7
  1. Inside of our Signup.js

    1. Configure useState hook for email, password and confirmPassword, set default state to ""
    2. In our Return we will use the Box Component from MUI core
    3. Import Box and add the following attributes
    4. Import TextField and put inside of our Box with the following attributes
    5. Copy TextField and Paste 2 times and edit for setPassowrd and confirmPassword
    6. Add a MUI Button next, import and add the Handle Submit onClick
    7. Check your Modal > SignUP and confirm our UI looks good

MUI MODAL with SIGNUP Code

1return (
2  <Box p={3} style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
3    <TextField
4      variant="outlined"
5      type="email"
6      label="Enter Email"
7      value={email}
8      onChange={(e) => setEmail(e.target.value)}
9      fullWidth
10    ></TextField>
11    <TextField
12      variant="outlined"
13      type="password"
14      label="Enter Password"
15      value={password}
16      onChange={(e) => setPassword(e.target.value)}
17      fullWidth
18    ></TextField>
19    <TextField
20      variant="outlined"
21      type="password"
22      label="Confirm Password"
23      value={confirmPassword}
24      onChange={(e) => setConfirmPassword(e.target.value)}
25      fullWidth
26    ></TextField>
27    <Button
28      variant="contained"
29      size="large"
30      style={{ backgroundColor: '#EEBC1D' }}
31      onClick={handleSubmit}
32    >
33      Sign Up
34    </Button>
35  </Box>
36);
37
  1. Setup Our Login.js

  2. Copy our return Code and state from SignUp.js

  3. Remove useState and TextField with ConfirmPassword References, we won't need it

  4. Create handleSubmit const

  5. confirm handleClose is a prop in Login

Login.js

1import React, { useState } from 'react';
2import { Box, Button, TextField } from '@material-ui/core';
3
4const Login = ({ handleClose }) => {
5  const [email, setEmail] = useState('');
6  const [password, setPassword] = useState('');
7
8  const handleSubmit = () => {};
9
10  return (
11    <Box
12      p={3}
13      style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}
14    >
15      <TextField
16        variant="outlined"
17        type="email"
18        label="Enter Email"
19        value={email}
20        onChange={(e) => setEmail(e.target.value)}
21        fullWidth
22      ></TextField>
23      <TextField
24        variant="outlined"
25        type="password"
26        label="Enter Password"
27        value={password}
28        onChange={(e) => setPassword(e.target.value)}
29        fullWidth
30      ></TextField>
31
32      <Button
33        variant="contained"
34        size="large"
35        style={{ backgroundColor: '#EEBC1D' }}
36        onClick={handleSubmit}
37      >
38        Sign Up
39      </Button>
40    </Box>
41  );
42};
43
44export default Login;
45

HandleSubmit PW Logic on SignUp

  1. Inside of HandleSugbmit lets add pw logic if (password !== confirmPassword)

  2. Next we want to add a SnackBar alert from MUI to prompt

    1. Before we can implement we want to create a Context for our Alerting
    2. Inside CryptoContext alert/setAlert state with {open: false, message: '', type: 'success'}
    3. Remember to add the value into our provider to be passed down to our children.

Updated Context with Alerting

1const [alert, setAlert] = useState({
2  open: false,
3  message: '',
4  type: 'success',
5});
6
7return (
8  <Crypto.Provider
9    value={{ currency, setCurrency, symbol, coins, loading, alert, setAlert }}
10  >
11    {children}
12  </Crypto.Provider>
13);
14
  1. New Alert.js Component Setup
    1. Create the component named Alert.js inside Components folder
    2. Import alert, setAlert from our CryptoState()
    3. Inside our return lets add the Snackbar from MUI
    4. Copy the JS example Snackbar code and paste inside of Alert.js
      • Just copy the logic, no styles or return code needed
    5. Remove open/setOpen state, it already inside our alert state.
    6. Remove default handleClick also
    7. Change setOpen(false) to setAlert({open: false}) to match our logic in cryptoState
    8. copy props from example code too, open, autoHideDuration, onClose
    9. Import MuiAlert and put inside our snackbar
    10. Add props (see example below)
    11. Finally add {alert.message} as the content for our MuiAlert Component

Completed Alert.js Example

1import { Snackbar } from '@material-ui/core';
2import React from 'react';
3import { CryptoState } from '../CryptoContext';
4import MuiAlert from '@material-ui/lab/Alert'
5
6const Alert = () => {
7  const { alert, setAlert } = CryptoState();
8
9
10  const handleClose = (event, reason) => {
11    if (reason === 'clickaway') {
12      return;
13    }
14
15    setAlert({open: false});
16  return (
17        <Snackbar
18          open={alert.open}
19          autoHideDuration={3000}
20          onClose={handleClose}
21        >
22          <MuiAlert
23            onClose={handleClose}
24            elevation={10}
25            variant="filled"
26            severity={alert.type}
27            >
28          {alert.message}
29          </MuiAlert>
30        </Snackbar>
31  )
32};
33
34export default Alert;
35
36

Adding our Alerts to SignUp.js

  1. import {CryptoState} from '../../CryptoContext.js'
  2. Lets destructure setAlert from CryptoState();
  3. Now we can add setAlert inside our password if block
  4. we will pass the type of alert we want when our PWs don't match
  5. Followed by an empty return
  6. Also we need to import our Alert into our APP.js
  7. Test your PW logic now on SignUp and see if your Alert pops

SignUp.js HandleSubmit

1const handleSubmit = () => {
2  if (password !== confirmPassword) {
3    setAlert({
4      open: true,
5      message: 'Passwords do not match',
6      type: 'error',
7    });
8    return;
9  }
10};
11

Adding Try Catch Block

  1. After our if/password check we want to add a try/catch but still iside our handleSubmit function

  2. Insided of our try {} lets add

    1. const result = await createuserWithEmailAndPassword()
    2. Add async to our handleSubmit before our argument ()
    3. Pass auth as the first arg and make sure to import
    4. Pass email and password as the last two arguments
    5. setAlert with a confirmation and welcome of the user with their email
    6. Pass handleClose() so it will timeout our alert last
    7. add error to your catch block arg
    8. setAlert inside our catch and pass the error message (see example below)
    9. Test SignUp and you should get Alerting
    10. Also lets console.log(result) at the bottom of our try block
    11. You can now see the information that result has access too, and how we are able to provide that information to the message of our Alert

Try/Catch Error Handling with Firebase

1import { auth } from '../../firebase';
2
3try {
4  const result = await createUserWithEmailAndPassword(auth);
5  setAlert({
6    open: true,
7    message: `Sign Up Successful. Welcome ${result.user.email}`,
8    type: 'success',
9  });
10  handleClose();
11} catch (error) {
12  setAlert({
13    open: true,
14    message: error.message,
15    type: 'error',
16  });
17  return;
18}
19

Configuring our Login.js HandleSubmit

  1. Destructure setAlert from our CryptoState()
  2. add if no email/password logic and set alert with return
  3. Now we can copy our SignUp catch logic as that will be the same
  4. we can create const result = await signInWithEmailAndPassword
  5. make sure to add async to the handleSubmit
  6. pass auth, email, password remember to import auth from firebase
  7. add console.log(result)to see our result object data on login
  8. Test with Login

Is User Logged In?

  1. We need to be able to tell if our user is now logged in or not or it will get confusing for your user experience

  2. Lets open CryptoContext again as we will need to be able to tap into this data throughout our App

  3. First lets import and add another useEffect

  4. lets call onAuthStateChanged(auth), this is a firebase method and pass auth and then a callback

  5. that callback will be passed user,

  6. if user setUser to user else set to null

    useEffect

1useEffect(() => {
2  onAuthStateChanged(auth, (user) => {
3    if (user) setUser(user);
4    else setUser(null);
5  });
6}, []);
7

Creating our User in Header

  1. Add user to our CryptoState destructure
  2. Now we have the user Object lets Wrap our AuthModal in jsx logic
    1{user ? 'Logout' : <AuthModal />}
  3. Now we can test to confirm Logout display on login

Removing Logout String and Adding UserSideBar

  1. Replace 'logout' with <UserSideBar>
  2. Create <UserSideBar> Component inside of our Authentication folder
  3. We should see the sidebar text inside our our button for now.
  4. Lets grab the Drawer code from MUIv4
  5. Copy the Source and add to our UserSideBar
  6. Now we need to remove the unneeded default code
    1. Remove all the list references
    2. Add hello inside of our Drawer for now
    3. Remove all options that aren't 'right'
    4. Delete all imports that we no longer need, should be yellow lines underneath your imports in your IDE
    5. it should show right on your button now and a small side bar

Configuring our SideBar

  1. Lets first replace the Button with an Avatar in our UserSideBar.js
    1. We will need the user from the context to get the users avatar photo
    2. we will import this Component form MUIv4
    3. Now lets replace <Button> with <Avatar> and pass the onClick with toggleDrawer and the default args, anchor & true
    4. Add src prop to avatar and pass our user object with the photoURL (See Example Below)
    5. Add alt prop and pass the userobject with displayName OR email

Example Avatar

1          <Avatar
2            onClick={toggleDrawer(anchor, true)}
3            style={{
4              height: 38,
5              width: 38,
6              marginLeft: 15,
7              cursor: 'pointer',
8              backgroundColor: '#EEBC1D',
9            }}
10            src={user.photoURL}
11            alt={user.displayName || user.email}
12          />
13          <Drawer
14            anchor={anchor}
15            open={state[anchor]}
16            onClose={toggleDrawer(anchor, false)}
17          >
18            Hello
19          </Drawer>
20
  1. Styling the UserSideBar and Avatar
    1. Remove all the styles we copied inside our UserSideBar.js useStyles object
      1. Copy Container Snippet (see below for code)
    2. Lets add the profile style for the profile class (see below for code)
    3. Lets add the picture style for the picture class (see below for code)
    4. Lets add the logout style for the logout button class (see below for code)
    5. Lets add the watchlist style for the watchlist class (see below for code)

Styling Example Code

1const useStyles = makeStyles({
2  container: {
3    width: 350,
4    padding: 25,
5    height: '100%',
6    display: 'flex',
7    flexDirection: 'column',
8    fontFamily: 'monospace',
9  },
10  profile: {
11    flex: 1,
12    display: 'flex',
13    flexDirection: 'column',
14    alignItems: 'center',
15    gap: '20px',
16    height: '92%',
17  },
18  picture: {
19    width: 200,
20    height: 200,
21    cursor: 'pointer',
22    backgroundColor: '#EEBC1D',
23    objectFit: 'contain',
24  },
25  logout: {
26    height: '8%',
27    width: '100%',
28    backgroundColor: '#EEBC1D',
29    marginTop: 20,
30  },
31  watchlist: {
32    flex: 1,
33    width: '100%',
34    backgroundColor: 'grey',
35    borderRadius: 10,
36    padding: 15,
37    paddingTop: 10,
38    display: 'flex',
39    flexDirection: 'column',
40    alignItems: 'center',
41    gap: 12,
42    overflowY: 'scroll',
43  },
44});
45
  1. Lets add classes.container to the first <div>inside of <Drawer>
  2. Lets add classes.profile to the second <div> inside of <Drawer>
  3. Copy our Avatar Tag and Paste inside our 2nd <div>.
    1. Remove the styles object and onClick
  4. After our 2nd Avatar tag, lets add a span (see example below for styles) that displays user.displayName or user.email

UserSideBar with Span

1<React.Fragment key={anchor}>
2  <Avatar
3    className={classes.picture}
4    onClick={toggleDrawer(anchor, true)}
5    style={{
6      height: 38,
7      width: 38,
8      cursor: 'pointer',
9      backgroundColor: '#EEBC1D',
10    }}
11    src={user.photoURL}
12    alt={user.displayName || user.email}
13  />
14  <Drawer
15    anchor={anchor}
16    open={state[anchor]}
17    onClose={toggleDrawer(anchor, false)}
18  >
19    <div className={classes.container}>
20      <div className={classes.profile}>
21        <Avatar
22          className={classes.picture}
23          src={user.photoURL}
24          alt={user.displayName || user.email}
25        />
26        <span
27          style={{
28            width: '100%',
29            fontSize: 25,
30            textAlign: 'center',
31            fontWeight: 'bolder',
32            wordWrap: 'break-word',
33          }}
34        >
35          {user.displayName || user.email}
36        </span>
37      </div>
38    </div>
39  </Drawer>
40</React.Fragment>
41

Adding our Logout Button

  1. Lets add Button after our 1st <div> after <span> on our UserSideBar.js
  2. Next we need to create our logOut Function
  3. inside logout lets add the firebase function signOut()
    1. this should auto import the signout method from firebase/auth
    2. Lets import {auth} from '../../firebase' and pass it into the signOut fucntion
  4. Add setAlert to our destructured objects from CryptoState so we can use it during logout
  5. Now we can add the setAlert fucntion and pass the example code below.
  6. Don't forget to toggleDrawer() so our drawer closes upon logout.

LogOut Button and LogOut Function for UserSideBar.js

1const logOut = () => {
2  signOut(auth);
3  setAlert({
4    open: true,
5    type: 'success',
6    message: 'Logout Successfull!',
7  });
8  toggleDrawer();
9};
10
11<Button variant="contained" className={classes.logout} onClick={logOut}>
12  Log Out
13</Button>;
14

Adding Google Authentication

  1. Inside of our AuthModal.js inside authentication folder
  2. Lets add a Box with the className of classes.google and import from MUI
  3. Add a span inside that box with OR
  4. Following our <span> lets add <GoogleButton>
  5. Import GoogleButton from 'react-google-button'
  6. lets create an empty function after our handleChange named signInWithGoogle
  7. Test and going to login prompt, confirm our Sign In with google Button Exists
  8. Now lets add the google styles to our AuthModal.js
1  google: {
2    padding: 24,
3    paddingTop: 0,
4    display: 'flex',
5    flexDirection: 'column',
6    textAlign: 'center',
7    gap: 20,
8    fontSize: 20,
9  },
10
  1. Adding Google Auth Provider

    1. const googleProvider = new GoogleAuthProvider()

      1. import googleAuthProvder from 'firebase/auth'
    2. create const signInWithPopup (this is a firebase function)

      1. import signInWithPopup from 'firebase/auth'
      2. pass auth as the first arg, don't forget to import
      3. pass googleProvider as our 2nd arg
    3. add .then()

      1. const setAlert from CryptoState()
        1. import CrpytoState
      2. Add handleClose() to shut the login prompt
    4. add .catch() for our error handling

      1. pass setAlert(see example for props)
      2. return
    5. Test the Google Auth Login now, it should work!

Google Provider Code

1
2  const { setAlert } = CryptoState();
3
4  const googleProvider = new GoogleAuthProvider();
5
6  const signInWithGoogle = () => {
7    signInWithPopup(auth, googleProvider)
8      .then((res) => {
9        setAlert({
10          open: true,
11          message: `Sign Up Successful. Welcome ${res.user.email}`,
12          type: 'success',
13        });
14        handleClose();
15      })
16      .catch((error) => {
17        setAlert({
18          open: true,
19          message: error.message,
20          type: 'error',
21        });
22        return;
23      });
24

Adding FIRESTORE for our WATCHLIST storage

  1. Go to Firebase Dashboard, under BUILD find FIRESTORE DATABASE. Click
  2. Swith radio start in test
  3. Test mode allows you more than 30 days of development for free
  4. Select a Server, default works
  5. Click Rule tab
    1. We want only logged in users to be able to add coins to their watchlist
    2. first remove the line that turns off the DB after 30 days.
    3. Next lets remove the code inside the first match block

Adding Endpoints to your Firstore DB

  1. add api endpoints you want to be asssociated with this data
  2. match /watchlist/{userId}
  3. We can create a function for our read and pass our userId to create a cleaner code

FireStore Endpoint Logic for Watchlist

1rules_version = '2';
2service cloud.firestore {
3  match /databases/{database}/documents {
4    match /watchlist/{userId}{
5    	allow read: if isLoggedIn(userId)
6      allow write: if request.auth.uid == userId
7    }
8  }
9    function isLoggedIn(userId){
10  return request.auth.uid == userId
11  }
12}
13

Add to Watchlist Button and Frontend Logic

  1. First open CoinPage.js inside Pages
  2. Lets add user to our CryptoState Destructure
  3. We only want to display the button IF the user is loggedIn
  4. Go underneath our <span> tag and add {}

Add to Watchlist Button

1{
2  user && (
3    <Button
4      variant="outlined"
5      style={{ width: '100%', height: 40, backgroundColor: '#EEBC1D' }}
6    >
7      Add to Watchlist
8    </Button>
9  );
10}
11

Adding Add to Watchlist Firebase Logic

  1. Inside our CoinPage.js lets create a const addToWatchList
  2. Inside addToWatchList we create another const coinRef
    1. add const coinRef = doc(db, 'watchlist', user.uid);
    2. doc is imported form our firestore
    3. db is imported from firebase
  3. Add a try catch block next
  4. add setDoc and import from firestore
    1. Pass our coinRef as the first arg that has all the doc data
    2. Pass an object with coins and ternirary logic for if a watchlist currently exists or needs to be created (see example below)
  5. Add watchlist and setWatchList to our cryptoContext useState
  6. pass it down via the Provider too
  7. now we can add watchlist to our destructure on coinpage
  8. after our setSoc lets add a setAlert to notify our user
  9. Lets add a variable inWatchList that checks if the coin are viewing is currently on the watchlist.
  10. Now we can Test and see if our firebase DB has the coin we added!

FireBase Watchlist Endpoint Code

1const addToWatchlist = async () => {
2  const coinRef = doc(db, 'watchlist', user.uid);
3
4  try {
5    await setDoc(coinRef, {
6      coins: watchlist ? [...watchlist, coin.id] : [coin?.id],
7    });
8    setAlert({
9      open: true,
10      message: `${coin.name} Added to the Watchlist !`,
11      type: 'success',
12    });
13  } catch (error) {
14    setAlert({
15      open: true,
16      message: error.message,
17      type: 'error',
18    });
19  }
20};
21

Watchlist Logic on CoinPage.js

1{
2  user && (
3    <Button
4      variant="outlined"
5      style={{ width: '100%', height: 40, backgroundColor: '#EEBC1D' }}
6      onClick={addToWatchlist}
7    >
8      {inWatchList ? 'Remove from Watchlist' : 'Add to Watchlist'}
9    </Button>
10  );
11}
12

Adding Watchlist Logic for If User Is Logged In

  1. On CryptoContext we want to create a useEffect

    1. if (user){} // If user is logged in

    2. add user to useEffect depedency array

    3. add our const coinRef = doc() //import doc

      1. pass db //import too
      2. pass endpoint // watchlist
      3. pass user id // user.uid
    4. Now we can add onSnapshot() and check the db for changes to our reference

      1. Add coinRef as first arg
      2. (coin) as our second arg
      3. add if coin.exists() setWatchlist
        1. pass coin.data().coins
      4. else log "no items in Watchlist"
    5. lets add var unsubscribe to our onSnapshot

    6. Last add a return anonymous function and call unsubscribe()

Watchlist Example

1useEffect(() => {
2  if (user) {
3    const coinRef = doc(db, 'watchlist', user.uid);
4
5    var unsubscribe = onSnapshot(coinRef, (coin) => {
6      if (coin.exists()) {
7        setWatchlist(coin.data().coins);
8      } else {
9        console.Console('No Items in Watchlist');
10      }
11    });
12    return () => {
13      unsubscribe();
14    };
15  }
16}, [user]);
17

Remove from Watchlist

  1. Now we need to implement removeFromWatchlist

    1. On our CoinPage lets add const removeFromWatchList function
    2. copy our logic from addToWatchList as it will be similiar
  2. Updating setDoc in our Try Block

    1. add coins: watchlist.filter((watch) => watch !== coin?.id)
    2. this takes our watchlist and updates the watchlist to have all coins but the coin we reference
    3. Add {merge: 'true'} to update hte doc with the new watchlist filtered data
    4. Update setALert to say "removed from watchlist instead of added"

Updated Remove From Watchlist Code

1const removeFromWatchList = async () => {
2  const coinRef = doc(db, 'watchlist', user.uid);
3
4  try {
5    await setDoc(
6      coinRef,
7      {
8        coins: watchlist.filter((watch) => watch !== coin?.id),
9      },
10      { merge: true }
11    );
12    setAlert({
13      open: true,
14      message: `${coin.name} Removed the Watchlist !`,
15      type: 'success',
16    });
17  } catch (error) {
18    setAlert({
19      open: true,
20      mesage: error.message,
21      type: 'error',
22    });
23  }
24};
25

Displaying our Watchlist items in sidebar

  1. Go to UserSideBar.js
  2. Lets add our watchlist from CryptoState so we can tap into our watchlist coins
  3. under our Watchlist span
    1. add {coins.map(coin => {})}
    2. add if watchlist includes (coin.id)
    3. return a <div> with classes.coin
    4. inside that div, put a span with {coin.name}
    5. add another span after with style (see example code)
    6. inside that span put {symbol} from our Context API and import
    7. After symbol Paste our numberWithCommas function we cretaed earlier and pass coin.current_price.toFixed(2) and import.
    8. We need an ICON now to Delete a Coin from the Watchlist
    9. npm i react-icons --force
    10. import {AiFillDelete} from 'react-icons/ai'
    11. Add coin styles (see github) to UserSideBar

Remove Watchlist Coin from UserSideBar Code

1<div className={classes.watchlist}>
2  <span style={{ fontSize: 15, textShadow: '0 0 5px black' }}>Watchlist</span>
3  {coins.map((coin) => {
4    if (watchlist.includes(coin.id))
5      return (
6        <div className={classes.coin}>
7          <span>{coin.name}</span>
8          <span style={{ display: 'flex', gap: 8 }}>
9            {symbol} {numberWithCommas(coin.current_price.toFixed(2))}
10            <AiFillDelete
11              style={{ cursor: 'pointer' }}
12              fontSize="16"
13              onClick={() => removeFromWatchlist(coin)}
14            />
15          </span>
16        </div>
17      );
18    else return <></>;
19  })}
20</div>
21

Remove from watchlist

  1. Lets Copy our RemoveFromWatchlist code from CoinPage.js
  2. We want to add coin as the arg1 for our pasted function
  3. import doc, db, and setdoc
  4. add removeFromWatchlist function to onClick for our AiFillDelete and pass coin as the arg

Cons of Google Firebase

  1. If not properly managed, the cost of maintaining Firebase on a pay-as-you-go service accumulates as reads and writes increase. So maintenance costs can spike at some points.
  2. It's hard to export data stored in Firestore into another database. Even if you eventually find a way, it often requires a high level of technicality. Plus, it can be quite costly, too.
  3. It can be less platform-agnostic, as it delves more towards Android than iOS.
  4. The larger the query result gets, the messier and slower things become.

Noteables

  • With Firebase, it's pretty simple to connect and use built-in third-party authentication providers, including Google, Facebook, Twitter, among others.

Learn more about it here