DEV Community

fatima
fatima

Posted on • Updated on

Phase 2: Portfolio Project

****

Hello there. I am excited to post about my first react project!
the project requirements as fallow :

  1. You must make a single page application (only one index.html
    file) using create-react-app.

  2. Your app should use at least 5 components in a way that keeps
    your code well organized.

  3. There should be at least 3 client-side routes using React
    Router. Be sure to include a nav bar or other UI element that
    allows users to navigate between routes.

  4. Use a json-server to create a RESTful API for your backend and
    make both a GET and a POST request to the json server. Use a
    form to make your post request, specifically a controlled
    form/component. Additionally, you may choose to incorporate
    data from an external API but it is not required.

  5. Add some styling: you're encouraged to write your CSS from
    scratch, either by using styled components or writing CSS
    files and using id/className to style your elements. You can
    also incorporate a UI framework (like React Bootstrap,
    Semantic UI, or Material UI) if you prefer.

INTRO

Before we start working on the project let's first give a brief introduction to React so we can understand what are we working with

what is React

React is a declarative, efficient, and flexible JavaScript library created by Facebook to help make web applications fast and efficient with minimal coding effort.

Simple to learn and use

React comes with an excellent deliver of documentation and tutorials. Anyone who know JavaScript can without difficulty apprehend React and begin the usage of it in only a few weeks.

Reusable components

React enables a developer to divide an app into smaller components that can be reused later, thereby reducing the codebase.

virtual DOM
For any framework, DOM manipulation is one of the most complex tasks, especially when the application is large. React addresses this problem by using the a Virtual DOM, which is mainly a lightweight copy of the Real DOM. It is only an in-memory representation that is not displayed on the screen.

Rather than rendering the entire DOM again, React compares changes in the Virtual DOM and then renders it in the Real DOM similarly.

phase2 project (coffee shop )

Let's start talking about our project process now that we've established what react is and how functional it is.

In this blog we will create a simple React app that can be used Post/delete/update a coffee list .

Setup

I used npx create-react-app coffee-shop-phase2-project to create my app. Then I used cd coffee-shop-phase2-project to get to my app repository, code . to open my app in Visual Studio, and npm start to load it in the browser.

After that, I deleted the following files:

  • src/App.css

  • src/App.test.js

  • src/logo.svg

  • src/setupTests.js

Then I adjusted my App.js file to look like this:

Image description

For this project, I used Material UI, a fantastic library for writing CSS-in-JS. You might want to use it as well if you're retracing my steps here. Runnpm install @material-ui/core to get it. However, you can also use regular CSS. It makes no difference.

After this step ,I started building my other required components such as Crad.js, Home.js, ItemForm.js, MenuList, and NavBar using the command touch component-name.

The App component

The<App/> component was to be the main component (parent component). It would have a single state field, so I imported useState from react using import React, {useState} from "react" I then declared the state variable leaving my App.js component like this :

Image description

The Menulist component

The <App/> component would then pass dawn items as props to <Menulist/> component which would then map over the items array, and render a single component for each.
And i've used Material UI in this component to style my cards with Grids, it looked like this:

Image description

The Cards component

I focused mainly on styling my cards in this component, and I destructed the item that was passed dawn as propas from the <Menulist/> component so that I could place each one in the correct area.
So after, the cards component looked like this:

Image description

The JSON file

My next step here was to create the Json file because it's one of the lab requirements I've chosen to create and start working on my fetch requests before moving on to the <itemForm /> component.

Image description

The ItemForm component

Since our json file is now ready, we can make our fetch requests. The first one I want to work on is the post request in my <itemform/>. It's not the best thing to start with; you might want to start with a get request, but since my item form component will only be responsible for posting my data to the backend, I've decided to start with that.

The first step is to create a handleAddItem function in the App/> component, then send the entire function as props to the ItemForm/> component.

Image description

After passing down the handle add function, it's time to set the items Data state, importing the usestate from react using import React useState from "react"; and also importing the styling tools from Matrial UI. After setting the state, styling, and sending the fetch request, the <ItemForm/> component should look like this:

import React, { useState } from "react";
import { FormControl, Input, InputLabel, Button, makeStyles } from '@material-ui/core'



const useStyles = makeStyles((theme) => ({
  root: {
    "& > *": {
      margin: theme.spacing(5),

    }
  }
}));

const image = "https://images5.alphacoders.com/905/905439.jpg"
const styles = {
  container: {
    backgroundImage: `url(${image})`,
    backgroundRepeat: "no-repeat",
    backgroundSize: "contain",
    height: "100vh",
    width: "cover",
    backgroundSize: "cover",
    backgroundPosition: 'center',

  },
}

function ItemForm({ handleAddItem }) {
  const [name, setName] = useState("");
  const [description, SetDescription] = useState("")
  const [image, setImage] = useState("")
  const [price, setPrice] = useState("")

  function handleSubmit(e) {
    e.preventDefault();

    const itemData = {
      name: name,
      image: image,
      description: description,
      price: `${price}$`,
      isInCart: false,
    };
  //clear all input values in the form
  setName('');
  SetDescription('');
  setImage('');
  setPrice('');





    // console.log("name:", name);
    // console.log("discribtion:", discribtion);

    fetch(" http://localhost:3001/coffies", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(itemData),
    })
      .then((r) => r.json())
      .then((newItem) => handleAddItem(newItem));


  }

  const classes = useStyles();



  return (
    <>

      <form className={classes.root} onSubmit={handleSubmit}>
        <FormControl

        >
          <InputLabel>Name</InputLabel>
          <Input
            value={name}
            onChange={(e) => setName(e.target.value)} />
        </FormControl>
        <FormControl>
          <InputLabel>image_url</InputLabel>
          <Input
            value={image}
            onChange={(e) => setImage(e.target.value)} />
        </FormControl>

        <FormControl variant="outlined" color="white">
          <InputLabel>description</InputLabel>
          <Input
            value={description}
            onChange={(e) => SetDescription(e.target.value)}
            label="describtion"
          />
        </FormControl>
        <FormControl variant="outlined">
          <InputLabel>price</InputLabel>
          <Input
            id="component-filled"
            value={price}
            onChange={(e) => setPrice(e.target.value)}
            label="price"
          />
        </FormControl>
        <Button color="primary" type="submit"
          style={{ top: 15, right: 20 }}
        >Add to List</Button>
      </form>

      <div style={styles.container}>

      </div>
    </>
  );
}

export default ItemForm;
Enter fullscreen mode Exit fullscreen mode

*The Get/Detete/Patch Ftech request *

The last thing I needed to do , at that point, was make the fetch get/delete requests in the <App/> component

  1. The Get request :

In this case, the useEffect hook is required, so the first step is to import it from React with import React, {useEffect, useState} from "react";then the get request:

useEffect(() => {
        fetch("http://localhost:3001/coffies")
            .then((r) => r.json())
            .then((items) => setItems(items));
    }, []);
Enter fullscreen mode Exit fullscreen mode

Our page browser would look like this as a result of the Get request:

Image description

  1. The Delete request:

The delete request function (handleDeletetItem function in this case) will take id as an argument and send a delete request to the specific id. After the second .thenThe array of items will then be iterated through, returning only those that do not match the id of the delete request.

function handleDeleteItem(id) {
        fetch(` http://localhost:3001/coffies/${id}`, {
            method: "DELETE",
        })
            .then((r) => r.json())
            .then(() => {
                const updatedQuestions = items.filter((item) => item.id !== id);
                setItems(updatedQuestions);
            })


    }
Enter fullscreen mode Exit fullscreen mode

This handleDeleteItem function will be passed dawn as a prop to <Menulist/>component , who will then pass dawn to the <Card/>component, leaving the <Card/> component fallow.

Image description

  1. The Patch request:

The Patch request will be located in the <Cards/>component because this is where the Add to card button is located and I wanted to change the text content on the button every time it was clicked as well as change the isInCart value from false to true,

In order for our state to be updated with changing values, we must create a function in the App component called handleUpdateItem, which will map through the array of items and return the updated value of each item.

 function handleUpdateItem(updatedItem) {
        const updatedItems = items.map((item) => {
            if (item.id === updatedItem.id) {
                return updatedItem;
            } else {
                return item;
            }
        });
        setItems(updatedItems);
    }
Enter fullscreen mode Exit fullscreen mode

This function will then be passed as a prop to the cards component, which will use it to update the state value with the patch request made here.

import React from 'react';
import { Card, CardActions, CardContent, Button, CardMedia, Typography } from "@material-ui/core";


function Cards({ item, handleDeleteItem, handleUpdateItem }) {

    const { id, description, name, image, price } = item


    function handleDeleteClick() {
        handleDeleteItem(id)

    }

    function handleAddToCartClick() {

        fetch(`http://localhost:3001/coffies/${item.id}`, {
            method: "PATCH",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify({
                isInCart: !item.isInCart,
            }),
        })
            .then((r) => r.json())
            .then((updatedItem) => handleUpdateItem(updatedItem));
    }


    return (


        <Card
        >


            <CardMedia
                component="img"
                height="350"
                image={image}
            />
            <CardContent>
                <Typography gutterBottom variant="h5" component="div">
                    {name}
                </Typography>
                <Typography variant="body2" color="text.secondary">
                    {description}
                </Typography>
                <Typography>
                    {price}
                </Typography>
            </CardContent>
            <CardActions>
                <Button size="small" className={item.isInCart ? "remove" : "add"} onClick={handleAddToCartClick}>
                    {item.isInCart ? "Remove From" : "Add to"}</Button>
                <Button size="small" onClick={handleDeleteClick}>delete</Button>
            </CardActions>
        </Card>

    );
}
export default Cards

Enter fullscreen mode Exit fullscreen mode

The NavBar component :

I know I said earlier that it was "the last thing I needed to do" but that was a dirty lie. I still needed to create a way for the user to navigate between browser components, and I needed to install React Router. To accomplish this, I Run npm install react-router-domin the terminal.
After that, I imported Link from react-router-dom and styled it with Matrial UI.

The would look as follows:

import React from "react";
import { Link } from "react-router-dom"
import { makeStyles, AppBar, Toolbar, Typography, CssBaseline } from "@material-ui/core"

const useStyles = makeStyles((theme) => ({
    navlinks: {
        marginLeft: theme.spacing(10),
        display: "flex",
    },
    link: {
        textDecoration: "none",
        color: "white",
        fontSize: "20px",
        marginLeft: theme.spacing(20),
        "&:hover": {
            color: "yellow",
            borderBottom: "1px solid white",
        },
    },
    logo: {
        flexGrow: "1",
        cursor: "pointer",
    },

    title: {
        flexGrow: 5
    }
}));


function NavBar() {
    const classes = useStyles();


    return (


        <AppBar position="static">
            <CssBaseline />
            <Toolbar>
                <Typography variant="h6" className={classes.logo}>
                    <h3 className={classes.title}> The Friendly Bean Coffee Shope</h3>
                </Typography>
                <div className={classes.navlinks} >
                    <nav>
                        <Link to="/"className={classes.link}>Home</Link>
                        <Link to="/ItemForm"className={classes.link}>ItemForm</Link>
                        <Link to="/MenuList"className={classes.link}>Menulist</Link>
                    </nav>
                </div>

            </Toolbar>
        </AppBar>


    );
}

export default NavBar;
Enter fullscreen mode Exit fullscreen mode

in the App component we well also need to import Switch and Route from Rreact router dom import { Switch, Route } from "react-router-dom"; the return of this componentr would look like this :

 return (

        <div>
            <NavBar  />
            <Switch>
                <Route exact path="/">
                    <Home />
                </Route>

                <Route path="/MenuList">
                    <MenuList handleDeleteItem={handleDeleteItem} items={items} handleUpdateItem={handleUpdateItem} />
                </Route>
                <Route path="/ItemForm">
                    <ItemForm handleAddItem={handleAddItem} />
                </Route>
                <Route path="*">
                    <h1>404 not found</h1>
                </Route>

            </Switch>

        </div>
    );
Enter fullscreen mode Exit fullscreen mode

We are not finished yet; one more step is required for it to function properly in ourindex.js We must import BrowserRouter from react router Dom import BrowserRouter from'react-router-dom; and place it around our App component, as shown:

Image description

After that, when we run npm start, our browser page will look like this:

Image description

This experience taught me a lot. It wasn't the most difficult task, but it allowed me to use many different React features and required a lot of thought about how to make components. I also liked how I was able to develop my styling ability using material ui for sure that was the fun part of all of this .
Thank you for reading you're welcome to check my git hub link for more details.

https://github.com/vatimetou-ebeke/Coffee-shop-phase2-project

Top comments (0)