How I built a blog site using React and Firebase

How I built a blog site using React and Firebase

Driving force

As a starter in web development, many times I find it hard to get the information I want surfing the net. It is not because of a lack of write-ups about the subject matter, but having read a lot of bulky write-ups, I seemed not to get what I wanted. That can be frustrating, 'gash'. So, I decided to build a blog site based on the AltSchool exam project, where developers can contribute - in the simplest form. And I also made the web app an open-source project for further improvement on the app.

Introduction

Code miller is a web application that allows a user to write a blog and save it on a firebase database. These saved blogs can be accessed by any user who successfully logged into the application. In this blog, I will show you how I built the web application from start to finish.

Overview of the application

Starting the app, the first page to be displayed is the home page with the navbar which consists of the links for the main pages across the web application, and also the sidebar which helps to display the titles of the existing blogs fetched from the firebase. The both navbar and the sidebar cut across the application. Other pages of the web application include a sign-up page that allows users to sign in to the application and a blog page that helps display the blogs available for the user with pagination implemented.

React part of the application

What is React?

The React.js framework is an open-source JavaScript framework and library developed by Facebook. It’s used for building interactive user interfaces and web applications quickly and efficiently with significantly less code than you would with vanilla JavaScript.

In React, you develop your applications by creating reusable components that you can think of as independent Lego blocks. These components are individual pieces of a final interface, which, when assembled, form the application’s entire user interface.

Getting started

To get started using React, you must have Node installed on your local development as a tool. You can click here to get Node installed on your local development.

How to create a React application?

You can create a React application using the Command Line Interface (CLI), by following this command:

npx create-react-app [app name]

Running the above command will create a React app with the preferred app name you used.

After that, you can move into the file you just created using this command:

cd [app name]
npm start or npm run start

After starting up the app, a default React app is displayed on the browser and you can start cleaning the app by deleting the unwanted files in your local development and start creating your own files.

This is the overview of the default app created:

To achieve the aim of building the app, some React libraries were installed such as:

  • React Error Boundary

  • React Router

  • React Helmet Async

All of the above libraries can be installed using this command:

npm install react-router-dom react-helmet-async react-error-boundary @mui/material @emotion/react @emotion/styled @mui/icons-material

Firebase part of the application

What is Firebase?

Firebase is a Google-backed application development software that enables developers to develop iOS, Android, and Web applications.

Used for in the application:

  • The first thing I utilized firebase for is to store the contribution blogs (data) made by the users of the application. From which those data can be later retrieved by any authenticated user.

  • It was also used for the authentication of a user so that the user experience can be personal. It is also responsible for handling whether a user would have access to the available blogs or not.

Getting started

Getting started using firebase requires a few steps. And to start using it, you can check this link. Sign up on the web and check its documentation.

How to install firebase on CLI

Just run this command:

npm install -g firebase-tools

For details, you can check this link. Though following the link under 'Getting started' will take you through the process of signing up, adding a project, and installing firebase.

How to add Firebase Database and Authentication

For adding the firebase database you can watch this video:

For adding the authentication you can watch this video:

Important Codes responsible for the application

This is what the index.js file looks like:

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter as Router } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Router>
        <App />
    </Router>
  </React.StrictMode>
);

For the App.js file, I have this code:

import React, { useState, useEffect, createContext } from "react";
import "./App.css";
import { Navbar } from "./components/LayoutComponent";
import { Sidebar } from "./components/LayoutComponent";
import AppRouter from "./components/routes/Index";
import { ErrorBoundary, useErrorHandler } from "react-error-boundary";
import { HelmetProvider } from "react-helmet-async";
import {
  ArrowUpward,
  ArrowCircleLeft,
  ArrowCircleRight,
} from "@mui/icons-material";
import {
  auth,
  provider,
  signInWithPopup,
  getRedirectResult,
  onAuthStateChanged,
  db,
} from "./firebase";

// create context
export const DbContext = createContext();
export const UserContext = createContext();

// ErrorBoundary
const ErrorBoundaryComponent = ({ error }) => {
  return (
    <div role="alert" className="errorBoundary">
      <h1 className="errorBoundary-title">Something went wrong!</h1>
      <p className="errorBoundary-message">{error.message}</p>
    </div>
  );
};
function App() {
  const handleError = useErrorHandler();

  // ErrorBoundary useEffect
  useEffect(() => {
    handleError();
  }, [handleError]);

  //Set state for the darkmode
  const [darkMode, setDarkMode] = useState(false);
  const [user, setUser] = useState(null);
  const [sidebar, setSidebar] = useState(false);

  // Handle sidebar
  const handleSidebar = () => {
    setSidebar((prev) => !prev);
  };

  //Handle the darkmode
  const handleDarkMode = (e) => {
    e.preventDefault();
    setDarkMode((prev) => !prev);
  };

  //Styles
  const darkModeStyle = {
    light: {
      foreground: "#000000",
      background: "#ffffff",
    },
    dark: {
      foreground: "#737737",
      background: "#000000",
    },
  };

  // Auth
  const handleAuth = () => {
    signInWithPopup(auth, provider)
      .then((result) => {})
      .catch((error) => {
        const errorMessage = error.message;
        console.log(errorMessage);
      });
  };
  useEffect(() => {
    getRedirectResult(auth)
      .then((result) => {})
      .catch((error) => {
        // Handle Errors here.
        const errorMessage = error.message;
        console.log(errorMessage);
      });
  }, []);

  useEffect(() => {
    //Get signedIn user
    onAuthStateChanged(auth, (user) => {
      if (user) {
        const { displayName, photoURL, email } = user;
        setUser({ displayName, photoURL, email });
      } else {
        console.log("user signed out");
        setUser(null);
      }
    });
  }, []);
  return (
    <DbContext.Provider value={db}>
      <div
        className="App"
        style={
          darkMode
            ? {
                backgroundColor: darkModeStyle.dark.background,
                color: darkModeStyle.dark.foreground,
              }
            : {
                backgroundColor: darkModeStyle.light.background,
                color: darkModeStyle.light.foreground,
              }
        }
      >
        <div id="topRegion-locator"></div>
        <div id="circleArrow">
          {sidebar ? (
            <ArrowCircleRight className="arrows" onClick={handleSidebar} />
          ) : (
            <ArrowCircleLeft className="arrows" onClick={handleSidebar} />
          )}
        </div>
        <ErrorBoundary FallbackComponent={ErrorBoundaryComponent}>
          <HelmetProvider>
            <UserContext.Provider value={user}>
              <Navbar toggle={handleDarkMode} darkMode={darkMode} />
              <div className="sidebarAppDiv">
                <Sidebar sidebar={sidebar} />
                <a href="#topRegion-locator" id="topRegion">
                  <ArrowUpward />
                </a>
                <AppRouter handleAuth={handleAuth} />
              </div>
            </UserContext.Provider>
          </HelmetProvider>
        </ErrorBoundary>
      </div>
    </DbContext.Provider>
  );
}
export default App;

This is the code responsible for the firebase integration:

import { initializeApp } from "firebase/app";
import { getFirestore } from "@firebase/firestore";
import {
  getAuth,
  signInWithPopup,
  GoogleAuthProvider,
  getRedirectResult,
  signOut,
  createUserWithEmailAndPassword,
  onAuthStateChanged,
} from "firebase/auth";

// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: "AIzaSyDfHMkuB4P4KoccHyM_6E1kHUYVVTKFAO4",
  authDomain: "miller16.firebaseapp.com",
  projectId: "miller16",
  storageBucket: "miller16.appspot.com",
  messagingSenderId: "914222060299",
  appId: "1:914222060299:web:9d8beeec83e30659ce080e"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
const provider = new GoogleAuthProvider();
const auth = getAuth();

export {
  provider,
  auth,
  signInWithPopup,
  getRedirectResult,
  onAuthStateChanged,
  signOut,
  createUserWithEmailAndPassword,
};

This code is responsible for both the Navbar and the Sidebar which cut across the whole web application:

import React, { useState, useContext, useEffect } from "react";
import { NavLink, Link } from "react-router-dom";
import { UserContext } from "../App";
import "./LayoutComponent.css";
import appLogo from "../images/logoImg.png";
import { collection, getDocs } from "@firebase/firestore";
import { DbContext } from "../App";
import {
  DarkMode,
  LightMode,
  HomeOutlined,
  Login,
  MenuOutlined,
  CancelOutlined,
  ExpandCircleDownSharp,
  ExpandLessRounded,
} from "@mui/icons-material";
import { auth } from "../firebase";
import CodingSchools from "./pages/courses/CodingSchools";

export const Navbar = (props) => {
  const user = useContext(UserContext);

  // States
  const [expandCourses, setExpandCourses] = useState(false);
  const [userDisplay, setUserDisplay] = useState(false);
  const [menu, setMenu] = useState(false);

  //Handle the dropdown menu
  const handleCoursesExpand = (e) => {
    e.preventDefault();
    setExpandCourses(true);
  };
  const handleCoursesClose = (e) => {
    e.preventDefault();
    setExpandCourses(false);
  };
  const handleMenu = () => {
    setMenu((prev) => !prev);
  };

  //Handle signout
  const handleSignout = (e) => {
    e.preventDefault();
    auth.signOut();
  };

  const handleUser = () => {
    setUserDisplay((prev) => !prev);
  };
  const handleUserHid = () => {
    setUserDisplay(false);
  };
  const CustomNavbarLink = ({ to, ...props }) => {
    let activeStyle = {
      color: "rgb(167, 52, 52)",
      transition: "all 0.3s",
    };
    return (
      <NavLink
        style={({ isActive }) =>
          isActive ? activeStyle : { textDecoration: "none" }
        }
        to={to}
        end
        {...props}
      />
    );
  };

  //Styles
  const style = {
    display: expandCourses ? "block" : "none",
  };
  return (
    <nav className="layoutNavbar">
      <ul>
        <li>
          <Link to="/">
            <img src={appLogo} alt="logo" className="logo" />
          </Link>
          <h1 className="logoText">Codemiller</h1>
          <CustomNavbarLink to="/" className="layoutNavbar-links">
            <HomeOutlined id="home" />
          </CustomNavbarLink>
          <CustomNavbarLink to="/blog" className="layoutNavbar-links" id="blog">
            <h1>Blogs</h1>
          </CustomNavbarLink>
          <div onClick={props.toggle}>
            {props.darkMode ? (
              <LightMode className="layoutNavbar-links" id="lightMode" />
            ) : (
              <DarkMode className="layoutNavbar-links" id="darkMode" />
            )}
          </div>
          <div className="coursesDiv" onMouseLeave={handleCoursesClose}>
            <div className="expand" onMouseOver={handleCoursesExpand}>
              <h1 to="/courses" id="courses">
                Courses
              </h1>
            </div>
            <div className="coursesDisplayDiv">
              {user ? (
                <div id="coursesContents" style={style}>
                  <CodingSchools />
                </div>
              ) : (
                <div
                  style={style}
                  className="layoutNavbar-links"
                  id="loginFirst"
                >
                  Login to view courses!
                </div>
              )}
            </div>
          </div>
          <div>
            {user ? (
              <img
                src={user.photoURL}
                alt="img"
                className="layoutNavbar-links"
                id="userImg"
                onMouseOver={handleUser}
              />
            ) : (
              <CustomNavbarLink
                to="/sign"
                className="layoutNavbar-links"
                id="login1"
              >
                <Login id="login" />
              </CustomNavbarLink>
            )}
          </div>
          <div
            className="layoutNavbar-user_div"
            style={{ display: userDisplay ? "block" : "none" }}
            onMouseLeave={handleUserHid}
          >
            <p>Signed in as:</p>
            <p>{user?.email}</p>
            <h2 onClick={handleSignout}>Sign out</h2>
          </div>
          {menu ? (
            <CancelOutlined className="menuIcon" onClick={handleMenu} />
          ) : (
            <MenuOutlined className="menuIcon" onClick={handleMenu} />
          )}
        </li>
        <div
          className="s-navbar"
          style={{ display: menu ? "block" : "none" }}
          onMouseLeave={handleMenu}
        >
          <div className="s-navbarFlex">
            <CustomNavbarLink
              to="/blog"
              className="s-layoutNavbar-links"
              id="s-blog"
            >
              <h1>Blogs</h1>
            </CustomNavbarLink>
            <div onClick={props.toggle}>
              {props.darkMode ? (
                <LightMode className="s-layoutNavbar-links" id="s-lightMode" />
              ) : (
                <DarkMode className="s-layoutNavbar-links" id="s-darkMode" />
              )}
            </div>
            <div className="s-coursesDiv">
              <div
                className="s-expand"
                onMouseOver={handleCoursesExpand}
                onClick={handleCoursesClose}
              >
                <h1 to="/courses" id="s-courses">
                  Courses
                </h1>
              </div>
              <div
                className="s-coursesDisplayDiv"
                onMouseLeave={handleCoursesClose}
              >
                {user ? (
                  <div id="s-coursesContents" style={style}>
                    <CodingSchools />
                  </div>
                ) : (
                  <div
                    style={style}
                    className="s-layoutNavbar-links"
                    id="s-loginFirst"
                  >
                    Login to view courses!
                  </div>
                )}
              </div>
            </div>
            <div>
              {user ? (
                <img
                  src={user.photoURL}
                  alt="img"
                  className="s-layoutNavbar-links"
                  id="s-userImg"
                  onMouseOver={handleUser}
                />
              ) : (
                <CustomNavbarLink to="/sign" className="s-layoutNavbar-links">
                  <Login id="s-login" />
                </CustomNavbarLink>
              )}
            </div>
            <div
              className="s-layoutNavbar-user_div"
              style={{ display: userDisplay ? "block" : "none" }}
              onMouseLeave={handleUserHid}
            >
              <p>Signed in as:</p>
              <p>{user?.email}</p>
              <h2 onClick={handleSignout}>Sign out</h2>
            </div>
          </div>
        </div>
      </ul>
    </nav>
  );
};

export const Sidebar = ({ sidebar }) => {
  // useContext
  const db = useContext(DbContext);
  const dbRef = collection(db, "contribution");
  const user = useContext(UserContext);

  // States
  const [openSource, setOpenSource] = useState(false);
  const [AllContributions, setAllContributions] = useState([]);

  //Handle open-source
  const handleOpenSource = () => {
    setOpenSource((prev) => !prev);
  };

  async function getAllContributions() {
    const contributions = await getDocs(dbRef);
    setAllContributions(
      contributions.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
    );
  }

  // useEffect
  useEffect(() => {
    getAllContributions();
  });

  const blogs = AllContributions.map((blog) => {
    return (
      <div key={blog.id} className="sidebarBlog-title_lists">
        <h2>{blog.contributionTitle}</h2>
      </div>
    );
  });
  return (
    <div
      className="sidebarWrapper"
      style={{
        marginLeft: sidebar ? "-350px" : "0",
        transition: "all 0.3s",
        position: sidebar ? "fixed" : "",
      }}
    >
      <h2 className="sidebarTitle">Blogs:</h2>
      <div className="sidebarHid">
        <h4 className="sidebarBlog-title_list">{blogs}</h4>
      </div>
      <div className="sidebarBlog-title_div"></div>
      <div className="sidebarFooterDiv">
        <div onClick={handleOpenSource}>
          <h2 className="sidebarFooter-heading">Open source</h2>
          <div className="sidebarFooter">
            <div>
              {openSource ? (
                <ExpandLessRounded className="sidebarFooterExpand" />
              ) : (
                <ExpandCircleDownSharp className="sidebarFooterExpand" />
              )}
            </div>
          </div>
        </div>
        <a
          href="https://github.com/michado2019/altschool-second-semester-exam"
          className="sidebarFooterBtn"
          style={{
            visibility: openSource ? "visible" : "hidden",
            opacity: openSource ? "1" : "0",
            transition: "all 0.5s",
          }}
        >
          Github Link
        </a>
      </div>
      <div className="appUser">
        {user ? (
          <h2 className="sidebarFooterUser">User: {user?.displayName}</h2>
        ) : (
          ""
        )}
      </div>
    </div>
  );
};

This is the code that controls the routing of the pages of the application:

import React, { lazy, Suspense, useState } from "react";
import { Routes, Route } from "react-router-dom";

const Loading = () => {
  return <div>Loading....</div>;
};

export default function AppRouter({ handleAuth }) {
  const Home = lazy(() => import("../pages/home/Home"));
  const Contribute = lazy(() => import("../pages/contribute/Contribute"));
  const Sign = lazy(() => import("../pages/sign/Sign"));
  const CodingSchools = lazy(() => import("../pages/courses/CodingSchools"));
  const ErrorPage = lazy(() => import("../pages/errorPage/ErrorPage"));
  const SignIn = lazy(() => import("../pages/signIn/SignIn"));
  const Blog = lazy(() => import("../pages/blog/Blog"));

  // State
  const [contribute, setContribute] = useState("");
  return (
    <div className="appRouter">
      <Suspense fallback={Loading}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route
            path="/contribute"
            element={
              <Contribute
                contribute={contribute}
                setContribute={setContribute}
                handleAuth={handleAuth}
              />
            }
          />
          <Route path="/blog" element={<Blog />} />
          <Route path="/sign" element={<Sign handleAuth={handleAuth} />} />
          <Route path="/signIn" element={<SignIn />} />
          <Route path="/courses" element={<CodingSchools />} />
          <Route path="*" element={<ErrorPage />} />
        </Routes>
      </Suspense>
    </div>
  );
}

This is the code for the sign page:

import React, { useEffect, useContext } from "react";
import "./Sign.css";
import { Helmet } from "react-helmet-async";
import { Link } from "react-router-dom";
import useForm from "../../hooks/useForm";
import { useNavigate } from "react-router-dom";
import googleImg from "../sign/assets/googleImg.png";
import { UserContext } from "../../../App";

export default function Sign({ handleAuth }) {
  // usecontext
  const userData = useContext(UserContext);

  //Navigation
  const navigate = useNavigate();

  //useForm data
  const { inputs, handleChange } = useForm({
    firstName: "",
    lastName: "",
    email: "",
    password: "",
  });

  // Handlers
  const handleSubmit = (e) => {
    e.preventDefault();
  };

  // useEffect
  useEffect(() => {
    if (userData) {
      navigate("/");
    }
  }, [navigate, userData]);
  return (
    <div className="signWrapper">
      <Helmet>
        <title>Sign in page</title>
        <meta name="description" content="Sign in here" />
        <link rel="canonical" href="/sign" />
      </Helmet>
      <div>
        <form className="signForm" onSubmit={handleSubmit}>
          <label htmlFor="first_name" className="signForm-labels">
            First name
          </label>
          <input
            type="text"
            placeholder="Enter your first name"
            className="signInput"
            id="first_name"
            name="firstName"
            value={inputs.firstName}
            onChange={handleChange}
          />
          <label htmlFor="Last_name" className="signForm-labels">
            Last name
          </label>
          <input
            type="text"
            placeholder="Enter your last name"
            className="signInput"
            id="last_name"
            name="lastName"
            value={inputs.lastName}
            onChange={handleChange}
          />
          <label htmlFor="email" className="signForm-labels">
            Email
          </label>
          <input
            type="text"
            placeholder="yourname@gmail.com"
            className="signInput"
            id="email"
            name="email"
            value={inputs.email}
            onChange={handleChange}
            required
          />
          <label htmlFor="email" className="signForm-labels">
            Password
          </label>
          <input
            type="password"
            placeholder="Choose a password"
            className="signInput"
            id="password"
            name="password"
            value={inputs.password}
            onChange={handleChange}
            required
          />
          <button className="signInput" id="btn__submit">
            Sign up
          </button>
        </form>
        <div className="signGoogle">
          <p>Sign in here:</p>
          <Link className="signLink">Sign in</Link>
          <img
            src={googleImg}
            alt="img"
            className="signGoogleImg"
            onClick={handleAuth}
          />
        </div>
      </div>
    </div>
  );
}

This is the code for the homepage:

import React, { useState } from "react";
import "./Home.css";
import { ExpandMore, ExpandLess } from "@mui/icons-material";
import { Link } from "react-router-dom";
import { Helmet } from "react-helmet-async";
import AppGuide from "../../AppGuide";

export default function Home() {
  // State
  const [expandFAQs, setExpandFAQs] = useState(false);
  const [guide, setGuide] = useState(false);

  //Handle the dropdown menu
  const handleFAQsExpand = (e) => {
    e.preventDefault();
    setExpandFAQs((prev) => !prev);
  };

  // Handle guide display
  const handleGuide = () => {
    setGuide((prev) => !prev);
  };

  //Styles
  const faqsDisplayStyles = {
    display: expandFAQs ? "block" : "none",
  };
  return (
    <div className="homeWrapper">
      <Helmet>
        <title>Homepage</title>
        <meta name="description" content="Welcome to my Homepage" />
        <link rel="canonical" href="/" />
      </Helmet>

      <div className="faqContactDiv">
        <div className="homeAbout-div">
          <div className="homeAbout">
            <h1 className="About-title">About</h1>
            <p className="About-details">
              <span className="codeMiller-span">Code miller</span> is an app
              that permits coders break codes complexity, such that starters
              would understand. And share via our{" "}
              <Link to="contribute" className="contributeLink">
                'contribute platform'
              </Link>
              .
            </p>
          </div>
          <div>
            <img src="aboutImg.jpg" alt="aboutImg" className="homeAbout-img" />
          </div>
        </div>
        <AppGuide guide={guide} />
        <div className="homeBigBtnsDiv">
          <div className="homeBigBtns">
            <Link to="contribute" className="contributeLink">
              <button className="homeBigBtn">Get Started</button>
            </Link>
            <button
              className="homeBigBtn"
              id="homeBigBtn"
              onClick={handleGuide}
            >
              Guide
            </button>
          </div>
        </div>
        <div className="homeFAQs">
          <h1 className="homeFAQs-gen_title">FAQs</h1>
          <div className="homeFAQs-main_flex">
            <div className="homeFAQs-flex">
              <div className="homeFAQs-div">
                <h4 className="homeFAQs-heading" onClick={handleFAQsExpand}>
                  HTML freguently asked questions
                </h4>
                <div className="homeFAQs-expands">
                  {expandFAQs ? <ExpandLess /> : <ExpandMore />}
                </div>
              </div>
              <p className="homeFAQs-click" style={faqsDisplayStyles}>
                <a
                  href="https://www.w3.org/html/wiki/FAQs"
                  target="_blank"
                  rel="noreferrer"
                >
                  Click me
                </a>
              </p>
              <div className="homeFAQs-div">
                <h4 className="homeFAQs-heading" onClick={handleFAQsExpand}>
                  CSS freguently asked questions
                </h4>
                <div className="homeFAQs-expands">
                  {expandFAQs ? <ExpandLess /> : <ExpandMore />}
                </div>
              </div>
              <p className="homeFAQs-click" style={faqsDisplayStyles}>
                <a
                  href="https://www.hwg.org/resources/faqs/cssFAQ.html"
                  target="_blank"
                  rel="noreferrer"
                >
                  Click me
                </a>
              </p>
              <div className="homeFAQs-div">
                <h4 className="homeFAQs-heading" onClick={handleFAQsExpand}>
                  JAVASCRIPT freguently asked questions
                </h4>
                <div className="homeFAQs-expands">
                  {expandFAQs ? <ExpandLess /> : <ExpandMore />}
                </div>
              </div>
              <p className="homeFAQs-click" style={faqsDisplayStyles}>
                <a
                  href="https://www.johnsmiley.com/jscript/faqs.htm"
                  target="_blank"
                  rel="noreferrer"
                >
                  Click me
                </a>
              </p>
            </div>
            <img src="qs.jpg" alt="qsImg" className="qsImg" />
            <img src="faqs.jpg" alt="faqImg" className="homeFAQs-img" />
          </div>
        </div>
        <div className="homeContacts">
          <h1 className="homeContacts-gen_title">Contact Us</h1>
          <div className="homeContacts-flex">
            <div className="homeContact-newsletter">
              <h3 className="homeContact-newsletter-title">
                Subscribe for our newsletter:
              </h3>
              <form className="subForm">
                <input
                  type="email"
                  placeholder="Enter your email"
                  className="homeContact-sub"
                />
                <button className="homeContact-sub_btn">Subscribe</button>
              </form>
              <form className="textarea">
                <textarea
                  placeholder="Enter your comment"
                  className=" homeContact-msg"
                  cols="20"
                  rows="5"
                />
                <button className="homeContact-comment_btn">Send</button>
              </form>
              <img
                src="contact2.webp"
                alt="contactImg"
                className="homeContacts-img2"
              />
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

The contribute page- the page that controls where a contributor can write his contribution. This is its code below:

import React, { useState, useContext, useEffect } from "react";
import AppGuide from "../../AppGuide";
import "./Contribute.css";
import { Link } from "react-router-dom";
import { addDoc, collection } from "@firebase/firestore";
import { DbContext } from "../../../App";
import { auth, signOut } from "../../../firebase";
import { UserContext } from "../../../App";

function Contribute({ contribute, setContribute, handleAuth }) {
  //useContext
  const db = useContext(DbContext);
  const dbRef = collection(db, "contribution");
  const user = useContext(UserContext);
  // State
  const [guide, setGuide] = useState(false);
  const [showForm, setShowForm] = useState(false);
  const [form, setForm] = useState({
    contributionTitle: "",
    contributionText: "",
    contributor: "",
    email: "",
    twitter: "",
  });

  // Handlers
  const handleGuide = () => {
    setGuide((prev) => !prev);
  };
  const handleFormShow = () => {
    setShowForm((prev) => !prev);
  };
  const handleChange = (e) => {
    e.preventDefault();
    const { name, value } = e.target;
    setForm({
      ...form,
      [name]: value,
    });
  };

  const handleContributionSubmit = async (e) => {
    e.preventDefault();
    if (contribute !== "") {
      await addDoc(dbRef, contribute);
      alert("Your contribution successfully saved! Thanks");
    }
  };
  const handleSignOut = () => {
    signOut(auth)
      .then(() => {
        // Sign-out successful.
      })
      .catch((error) => {
        // An error happened.
      });
  };

  const handleFormReset = () => {
    setForm({
      contributionTitle: "",
      contributionText: "",
      contributor: "",
      email: "",
      twitter: "",
    });
  };

  // useEffect
  useEffect(() => {
    if (form.twitter.length > 7) setContribute(form);
  }, [form, setContribute]);
  return (
    <div className="contributeWrapper">
      <div className="contributeFlex-1">
        <div className="contributeGuide-div">
          <h2 className="contributeGuide-heading">
            Click the 'Guide' button before contributing
          </h2>
          <div className="contributeGuideFlex">
            <button
              className="homeBigBtn"
              id="homeBigBtn"
              onClick={handleGuide}
            >
              Guide
            </button>
            {user ? (
              <div className="contributeFlex-2">
                <button
                  className="contributeGoogleBtn"
                  id="contributeGoogleBtn"
                  onClick={handleSignOut}
                >
                  Sign out
                </button>
              </div>
            ) : (
              <div className="contributeFlex-2">
                <button className="contributeGoogleBtn" onClick={handleAuth}>
                  Sign with Google
                </button>
              </div>
            )}
          </div>
        </div>
        <div
          style={{ display: guide ? "block" : "none" }}
          className="contributeGuide"
        >
          <AppGuide guide={guide} />
        </div>
      </div>
      {user ? (
        <h2 className="contributeAuthorizedUser">
          Hi, <span className="displayName">{user.displayName}</span>. You are
          now authorized to contribute!
        </h2>
      ) : (
        <h2 className="contributeAuthorizedUser">
          Sign in with google to be able to make your contribution
        </h2>
      )}
      <div className="contributeGuideDiv">
        <div className="contributeFlex-3">
          <button
            onClick={handleFormShow}
            style={{ display: user ? "block" : "none" }}
          >
            Contribute
          </button>
          <Link to="/">
            <button>Home</button>
          </Link>
          <button
            onClick={handleFormReset}
            style={{ display: user ? "block" : "none" }}
          >
            Reset form
          </button>
        </div>
        <div
          className="contributeFormDiv"
          style={{ display: showForm ? "none" : "block" }}
        >
          <form
            className="contributeForm"
            onSubmit={handleContributionSubmit}
            style={{ display: user ? "block" : "none" }}
          >
            <label className="contributeLabel">Title:</label>
            <input
              type="text"
              placeholder="Contribution title"
              className="contributeFormInput"
              onChange={handleChange}
              name="contributionTitle"
              value={form.contributionTitle}
              required
            />
            <label className="contributeLabel">Contribution:</label>
            <textarea
              className="contributeTextarea"
              placeholder="Contribute here...."
              onChange={handleChange}
              name="contributionText"
              value={form.contributionText}
              required
            />
            <label className="contributeLabel">Email:</label>
            <input
              type="email"
              placeholder="Enter your email"
              className="contributeFormInput"
              onChange={handleChange}
              name="email"
              value={form.email}
              required
            />
            <label className="contributeLabel">Contributor's name:</label>
            <input
              type="text"
              placeholder="Enter contributor's name"
              className="contributeFormInput"
              onChange={handleChange}
              name="contributor"
              value={form.contributor}
              required
            />
            <label className="contributeLabel">Twitter username:</label>
            <input
              type="text"
              placeholder="Enter twitter username"
              className="contributeFormInput"
              onChange={handleChange}
              name="twitter"
              value={form.twitter}
              required
            />
            <button id="contributeSubmitBtn" className="contributeFormInput">
              Contribute
            </button>
          </form>
        </div>
      </div>
    </div>
  );
}
export default Contribute;

And lastly, here is the code for Blog. js - responsible for the display of the blog data fetch from the database:

import React, { useState, useContext, useEffect } from "react";
import "./Blog.css";
import { Helmet } from "react-helmet-async";
import { collection, getDocs } from "@firebase/firestore";
import { DbContext, UserContext } from "../../../App";
import { NoBlog } from "../../Loading";
import twitterLogo from "../blog/assets/logo-3491390.png";
export default function Blog() {
  //useContext
  const db = useContext(DbContext);
  const dbRef = collection(db, "contribution");
  const user = useContext(UserContext);

  // State
  const [AllContributions, setAllContributions] = useState([]);
  const [page, setPage] = useState(1);

  // useEffect
  useEffect(() => {
    async function getAllContributions() {
      const contributions = await getDocs(dbRef);
      if (user)
        setAllContributions(
          contributions.docs.map((doc) => ({ ...doc.data(), id: doc.id }))
        );
    }
    getAllContributions();
  });

  // Pagination

  const perPage = 1;
  const pages = Math.ceil(AllContributions.length / perPage);
  const skip = page * perPage - perPage;
  return (
    <div
      className="blogWrapper"
      style={{ height: user ? "fit-content" : "130vh" }}
    >
      <Helmet>
        <title>Blogpage</title>
        <meta name="description" content="Welcome to my Blogpage" />
        <link rel="canonical" href="/blog" />
      </Helmet>
      <div className="blogContributeWrapper">
        {user ? (
          <div>
            {AllContributions.slice(skip, skip + perPage).map((doc) => {
              return (
                <div key={doc.id} className="blogDiv">
                  <h2 className="blogTitle">{doc.contributionTitle}</h2>
                  <p className="blogText">{doc.contributionText}</p>
                  <p className="blogContributor">
                    Contributor: <span id="contributor">{doc.contributor}</span>
                  </p>
                  <a
                    href={`https://twitter.com/${doc.twitter}`}
                    className="blogTwitter"
                  >
                    Follow me on twitter:{" "}
                    <span>
                      <img
                        src={twitterLogo}
                        alt="img"
                        className="blogTwitterImg"
                      />
                    </span>
                  </a>
                  <p className="pagination">
                    Pages: {page} of {pages}
                  </p>
                  <div className="blogBtnsDiv">
                    <button
                      className="blogBtns"
                      disabled={page <= 1}
                      onClick={() => setPage((prev) => prev - 1)}
                    >
                      Prev
                    </button>
                    <button
                      className="blogBtns"
                      disabled={page >= pages}
                      aria-disabled={page >= pages}
                      onClick={() => setPage((prev) => prev + 1)}
                    >
                      Next
                    </button>
                  </div>
                </div>
              );
            })}
          </div>
        ) : (
          <NoBlog />
        )}
      </div>
    </div>
  );
}

This is what the front page of the application looks like:

Conclusion

In conclusion, we have been able to create the Code miller app - which has the ability to take a contribution and store it in the firebase database, and retrieve the same when needed by a signed-up user.

This is the link to the source code: GitHub

Live link: https://altschool-second-semester-exam.vercel.app

Thanks for reading!